feat: Add static path and per-template style.css #3

Open
chanbakjsd wants to merge 1 commits from chanbakjsd/blgo:master into master
5 changed files with 82 additions and 3 deletions

1
.gitignore vendored

@ -1,2 +1,3 @@
config.json config.json
content/ content/
static/

@ -1,6 +1,12 @@
package handler package handler
import "net/http" import (
"fmt"
"net/http"
"os"
)
var fs = http.FileServer(http.Dir("static/"))
// Index is the handler that displays the index page. // Index is the handler that displays the index page.
func Index(w http.ResponseWriter, r *http.Request) { func Index(w http.ResponseWriter, r *http.Request) {
@ -13,5 +19,45 @@ func Handler(w http.ResponseWriter, r *http.Request) {
Index(w, r) Index(w, r)
return return
} }
if r.URL.Path == "/style.css" {
TemplateStyle(w, r)
return
}
if Static(w, r) {
return
}
Post(w, r) Post(w, r)
} }
// TemplateStyle is a handler that servers the style of the current template.
func TemplateStyle(w http.ResponseWriter, r *http.Request) {
if themeCSS == nil {
// 404 if the theme CSS doesn't exist as it's optional.
CurrentTheme.ExecuteTemplate(w, "404.tmpl", nil)
return
}
w.Header().Add("Content-Type", "text/css")
_, _ = w.Write(themeCSS)
}
// Static is a handler that serves static content if available.
// If it has served something (the static file or an error), it returns true.
func Static(w http.ResponseWriter, r *http.Request) bool {
fileName := "static" + r.URL.Path
// Check if the file exists and is not a directory.
info, err := os.Stat(fileName)
if os.IsNotExist(err) || (info != nil && info.IsDir()) {
return false
}
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
CurrentTheme.ExecuteTemplate(w, "500.tmpl", fmt.Errorf("error reading static folder: %w", err))
return true
}
// The file probably exist now. Even if there's a mismatch, the malicious attacker can only get a
// 404 or a directory listing.
fs.ServeHTTP(w, r)
return true
}

@ -1,6 +1,7 @@
package handler package handler
import ( import (
"fmt"
"net/http" "net/http"
"os" "os"
) )
@ -18,7 +19,7 @@ func Post(w http.ResponseWriter, r *http.Request) {
} }
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
CurrentTheme.ExecuteTemplate(w, "500.tmpl", err) CurrentTheme.ExecuteTemplate(w, "500.tmpl", fmt.Errorf("error reading content folder: %w", err))
return return
} }

@ -1,10 +1,19 @@
package handler package handler
import "html/template" import (
"html/template"
"io/ioutil"
"os"
"github.com/sirupsen/logrus"
)
// CurrentTheme is the set of template being used. // CurrentTheme is the set of template being used.
var CurrentTheme *template.Template var CurrentTheme *template.Template
// themeCSS is the CSS of the current theme.
var themeCSS []byte
// SetTheme parses the provided theme name and sets it as the current theme. // SetTheme parses the provided theme name and sets it as the current theme.
func SetTheme(themeName string) error { func SetTheme(themeName string) error {
var err error var err error
@ -17,5 +26,25 @@ func SetTheme(themeName string) error {
folder+"post.tmpl", // Page for posts. folder+"post.tmpl", // Page for posts.
) )
if err != nil {
return err
}
// Check if the style CSS exists and is not a directory.
info, err := os.Stat(folder + "style.css")
if os.IsNotExist(err) || (info != nil && info.IsDir()) {
return nil
}
f, err := os.Open(folder + "style.css")
if err != nil {
return err
}
defer func() {
err := f.Close()
if err != nil {
logrus.Fatalf("Error while closing theme CSS file: %v", err)
}
}()
themeCSS, err = ioutil.ReadAll(f)
return err return err
} }

@ -0,0 +1,2 @@
body { margin: 0 }
/* This is style.css of the debug template. */