alpha/main.go

118 lines
2.6 KiB
Go
Raw Normal View History

package main
2022-05-25 02:25:42 +00:00
import (
2022-05-28 00:12:28 +00:00
"fmt"
"io"
2022-05-25 02:25:42 +00:00
"log"
"net/http"
2022-05-28 00:12:28 +00:00
"os"
"path/filepath"
"strconv"
2022-05-27 23:34:48 +00:00
"strings"
2022-05-25 02:25:42 +00:00
"time"
)
type SessionProvider interface {
Create(user User, expr time.Duration) (string, error)
Get(key string) (User, error)
Refresh(key string, user User, expr time.Duration) error
}
type PageProvider interface {
Page(key string) (*Page, error)
Save(key string, page *Page) error
}
type RootHandler struct {
2022-05-28 00:12:28 +00:00
Sessions SessionProvider
Pages PageProvider
StaticDir string
2022-05-25 02:25:42 +00:00
}
2022-05-27 23:34:48 +00:00
type AdminHandler struct {
Sessions SessionProvider
}
func (h *AdminHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("admin route"))
}
2022-05-25 02:25:42 +00:00
func (h *RootHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
2022-05-27 23:34:48 +00:00
if strings.HasPrefix(r.URL.Path, "/admin") {
(&AdminHandler{
Sessions: h.Sessions,
}).ServeHTTP(w, r)
2022-05-25 02:25:42 +00:00
return
}
2022-05-27 23:34:48 +00:00
// attempt to serve from the managed pages
2022-05-25 02:25:42 +00:00
page, err := h.Pages.Page(r.URL.Path)
2022-05-27 23:34:48 +00:00
if err == nil {
w.Write(page.Contents)
2022-05-25 02:25:42 +00:00
return
}
2022-05-27 23:34:48 +00:00
// fall back to serving out of the static directory, but:
// 1. prevent the generated indexes from rendering
if strings.HasSuffix(r.URL.Path, "/") {
2022-05-28 00:12:28 +00:00
h.ErrorHandle(404, w)
2022-05-27 23:34:48 +00:00
return
}
// 2. prevent hidden paths from rendering
for _, seg := range strings.Split(r.URL.Path, "/") {
if strings.HasPrefix(seg, ".") {
2022-05-28 00:12:28 +00:00
h.ErrorHandle(404, w)
2022-05-27 23:34:48 +00:00
return
}
}
2022-05-28 00:12:28 +00:00
// 3. catch files that would 404 and serve our own 404 page
if !staticFileExists(filepath.Join(h.StaticDir, r.URL.Path)) {
h.ErrorHandle(404, w)
return
}
2022-05-27 23:34:48 +00:00
// finally, use the built-in fileserver to serve
2022-05-28 00:12:28 +00:00
fs := http.FileServer(http.Dir(h.StaticDir))
2022-05-27 23:34:48 +00:00
fs.ServeHTTP(w, r)
2022-05-25 02:25:42 +00:00
}
2022-05-28 00:12:28 +00:00
func (h *RootHandler) ErrorHandle(status int, w http.ResponseWriter) {
f, err := os.Open(filepath.Join(h.StaticDir, strconv.Itoa(status)+".html"))
if err == nil {
w.WriteHeader(status)
_, err = io.Copy(w, f)
if err != nil {
fmt.Fprintf(w, "Internal Server Error while loading %d page\n", status)
}
return
}
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.WriteHeader(404)
fmt.Fprintf(w, "%d\n", status)
}
func staticFileExists(name string) bool {
f, err := os.Open(name)
if err != nil {
return false
}
defer f.Close()
_, err = f.Stat()
return err == nil
}
func main() {
2022-05-25 02:25:42 +00:00
handler := &RootHandler{
2022-05-28 00:12:28 +00:00
Sessions: &Sessions{},
Pages: &Index{},
StaticDir: "./static",
2022-05-25 02:25:42 +00:00
}
handler.Pages.Save("foo", &Page{
Contents: []byte("foobar"),
})
2022-05-27 23:34:48 +00:00
handler.Pages.Save("index", &Page{
Contents: []byte("root"),
})
2022-05-25 02:25:42 +00:00
err := http.ListenAndServe(":8080", handler)
log.Fatalf("server error: %v", err)
}