package main import ( "log" "net/http" "strings" "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 { Sessions SessionProvider Pages PageProvider } type AdminHandler struct { Sessions SessionProvider } func (h *AdminHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { w.Write([]byte("admin route")) } func (h *RootHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if strings.HasPrefix(r.URL.Path, "/admin") { (&AdminHandler{ Sessions: h.Sessions, }).ServeHTTP(w, r) return } // attempt to serve from the managed pages page, err := h.Pages.Page(r.URL.Path) if err == nil { w.Write(page.Contents) return } // fall back to serving out of the static directory, but: // 1. prevent the generated indexes from rendering if strings.HasSuffix(r.URL.Path, "/") { http.NotFound(w, r) return } // 2. prevent hidden paths from rendering for _, seg := range strings.Split(r.URL.Path, "/") { if strings.HasPrefix(seg, ".") { http.NotFound(w, r) return } } // finally, use the built-in fileserver to serve fs := http.FileServer(http.Dir("./static")) fs.ServeHTTP(w, r) } func main() { handler := &RootHandler{ Sessions: &Sessions{}, Pages: &Index{}, } handler.Pages.Save("foo", &Page{ Contents: []byte("foobar"), }) handler.Pages.Save("index", &Page{ Contents: []byte("root"), }) err := http.ListenAndServe(":8080", handler) log.Fatalf("server error: %v", err) }