aboutsummaryrefslogtreecommitdiff
path: root/pkg/handler
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/handler')
-rw-r--r--pkg/handler/about/handler.go3
-rw-r--r--pkg/handler/auth/login.go4
-rw-r--r--pkg/handler/git/handler.go69
-rw-r--r--pkg/handler/router.go18
-rw-r--r--pkg/handler/static/handler.go63
5 files changed, 141 insertions, 16 deletions
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 a9be54c..d046d19 100644
--- a/pkg/handler/git/handler.go
+++ b/pkg/handler/git/handler.go
@@ -2,6 +2,7 @@ package git
import (
"bytes"
+ "compress/gzip"
"errors"
"fmt"
"io"
@@ -37,6 +38,7 @@ type (
GetRootReadme() string
GetSyntaxHighlight() string
GetOrderBy() config.OrderBy
+ GetHostname() string
}
)
@@ -47,7 +49,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())
@@ -89,7 +91,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")
@@ -115,7 +117,51 @@ func (g *GitHandler) Archive(w http.ResponseWriter, r *http.Request) error {
return nil
}
-func (g *GitHandler) Summary(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")
+
+ if r.URL.RawQuery == "service=git-receive-pack" {
+ ext.BadRequest(w, r, "no pushing allowed")
+ return nil
+ }
+
+ if path == "info/refs" && r.URL.RawQuery == "service=git-upload-pack" && r.Method == "GET" {
+ w.Header().Set("content-type", "application/x-git-upload-pack-advertisement")
+
+ err := g.gitService.WriteInfoRefs(r.Context(), name, w)
+ if err != nil {
+ slog.Error("Error WriteInfoRefs", "error", err)
+ }
+ } else if path == "git-upload-pack" && r.Method == "POST" {
+ w.Header().Set("content-type", "application/x-git-upload-pack-result")
+ w.Header().Set("Connection", "Keep-Alive")
+ w.Header().Set("Transfer-Encoding", "chunked")
+ w.WriteHeader(http.StatusOK)
+
+ reader := r.Body
+
+ if r.Header.Get("Content-Encoding") == "gzip" {
+ var err error
+ reader, err = gzip.NewReader(r.Body)
+ if err != nil {
+ return err
+ }
+ defer reader.Close()
+ }
+
+ err := g.gitService.WriteUploadPack(r.Context(), name, reader, w)
+ if err != nil {
+ slog.Error("Error WriteUploadPack", "error", err)
+ }
+ } else if r.Method == "GET" {
+ return g.Summary(w, r)
+ }
+
+ return nil
+}
+
+func (g *GitHandler) Summary(w http.ResponseWriter, r *ext.Request) error {
ext.SetHTML(w)
name := r.PathValue("name")
ref, err := g.gitService.GetHead(name)
@@ -149,13 +195,14 @@ func (g *GitHandler) Summary(w http.ResponseWriter, r *http.Request) error {
Tags: tags,
Branches: branches,
Commits: commits,
+ Hostname: g.config.GetHostname(),
},
}
templates.WritePageTemplate(w, gitList, r.Context())
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)
@@ -199,7 +246,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")
@@ -230,7 +277,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")
@@ -259,7 +306,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")
@@ -302,6 +349,7 @@ func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) error {
formatter := html.New(
html.WithLineNumbers(true),
html.WithLinkableLineNumbers(true, "L"),
+ html.WithClasses(true),
)
iterator, err := lexer.Tokenise(nil, string(file))
@@ -327,7 +375,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")
@@ -350,7 +398,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")
@@ -372,7 +420,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")
@@ -393,6 +441,7 @@ func (g *GitHandler) Commit(w http.ResponseWriter, r *http.Request) error {
formatter := html.New(
html.WithLineNumbers(true),
html.WithLinkableLineNumbers(true, "L"),
+ html.WithClasses(true),
)
iterator, err := lexer.Tokenise(nil, diff)
diff --git a/pkg/handler/router.go b/pkg/handler/router.go
index e461922..1fbc4e3 100644
--- a/pkg/handler/router.go
+++ b/pkg/handler/router.go
@@ -1,6 +1,7 @@
package handler
import (
+ "fmt"
"net/http"
serverconfig "git.gabrielgio.me/cerrado/pkg/config"
@@ -10,6 +11,7 @@ import (
"git.gabrielgio.me/cerrado/pkg/handler/git"
"git.gabrielgio.me/cerrado/pkg/handler/static"
"git.gabrielgio.me/cerrado/pkg/service"
+ "git.gabrielgio.me/cerrado/templates"
)
// Mount handler gets the requires service and repository to build the handlers
@@ -31,6 +33,14 @@ func MountHandler(
return nil, err
}
+ cssStaticHandler, err := static.ServeStaticCSSHandler(
+ configRepo.GetSyntaxHighlight(),
+ configRepo.GetSyntaxHighlightDark(),
+ )
+ if err != nil {
+ return nil, err
+ }
+
mux := ext.NewRouter()
mux.AddMiddleware(ext.Compress)
mux.AddMiddleware(ext.Log)
@@ -45,8 +55,14 @@ func MountHandler(
}
mux.HandleFunc("/static/{file}", staticHandler)
+ // add slug and session so css file can be cached forever.
+ // Slug follow commit id, which is update every new version
+ // Session is update every time server restarts, this allows the css to be
+ // cached forever but refresh if the admin updates the server configuration.
+ mux.HandleFunc(fmt.Sprintf("/static/theme.%s%s.css", templates.Session, templates.Slug), cssStaticHandler)
mux.HandleFunc("/{name}/about/{$}", gitHandler.About)
- mux.HandleFunc("/{name}/", gitHandler.Summary)
+ mux.HandleFunc("/{name}", gitHandler.Multiplex)
+ mux.HandleFunc("/{name}/{rest...}", gitHandler.Multiplex)
mux.HandleFunc("/{name}/refs/{$}", gitHandler.Refs)
mux.HandleFunc("/{name}/tree/{ref}/{rest...}", gitHandler.Tree)
mux.HandleFunc("/{name}/blob/{ref}/{rest...}", gitHandler.Blob)
diff --git a/pkg/handler/static/handler.go b/pkg/handler/static/handler.go
index 361f690..6cc884e 100644
--- a/pkg/handler/static/handler.go
+++ b/pkg/handler/static/handler.go
@@ -1,6 +1,9 @@
package static
import (
+ "bytes"
+ "fmt"
+ "io"
"io/fs"
"mime"
"net/http"
@@ -8,6 +11,9 @@ import (
"git.gabrielgio.me/cerrado/pkg/ext"
"git.gabrielgio.me/cerrado/static"
+ "github.com/alecthomas/chroma/v2"
+ "github.com/alecthomas/chroma/v2/formatters/html"
+ "github.com/alecthomas/chroma/v2/styles"
)
func ServeStaticHandler() (ext.ErrorRequestHandler, error) {
@@ -16,7 +22,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 +30,60 @@ 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
}
+
+func ServeStaticCSSHandler(lightTheme, darkTheme string) (ext.ErrorRequestHandler, error) {
+ var (
+ lightStyle = styles.Get(lightTheme)
+ darkStyle = styles.Get(darkTheme)
+ formatter = html.New(
+ html.WithCSSComments(false),
+ )
+ )
+
+ return func(w http.ResponseWriter, r *ext.Request) error {
+ ext.SetMIME(w, "text/css")
+ w.Header().Add("Cache-Control", "max-age=31536000")
+
+ // use buffer so this function can fail before writing to http.ResponseWriter
+ var buffer bytes.Buffer
+
+ var style *chroma.Style
+ style = darkStyle
+ buffer.Write([]byte("[data-bs-theme=\"dark\"] {\n"))
+ err := formatter.WriteCSS(&ws{&buffer}, style)
+ if err != nil {
+ return err
+ }
+ buffer.Write([]byte("}\n"))
+
+ style = lightStyle
+ buffer.Write([]byte("[data-bs-theme=\"light\"] {\n"))
+ err = formatter.WriteCSS(&ws{&buffer}, style)
+ if err != nil {
+ return err
+ }
+ buffer.Write([]byte("}"))
+
+ _, err = io.Copy(w, &buffer)
+ if err != nil {
+ return err
+ }
+
+ return nil
+ }, nil
+}
+
+type ws struct {
+ inner io.Writer
+}
+
+// This is very cursed, and rely on the fact that it writes every css rule at time.
+// it adds & to the begging so it can be nested by the ServeStaticCSSHandler.
+// This will allow the follow bootstrap data-bs-theme.
+func (w *ws) Write(p []byte) (n int, err error) {
+ return fmt.Fprintf(w.inner, "& %s", string(p))
+}