aboutsummaryrefslogtreecommitdiffstats
path: root/internal/web/server.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/web/server.go')
-rw-r--r--internal/web/server.go37
1 files changed, 29 insertions, 8 deletions
diff --git a/internal/web/server.go b/internal/web/server.go
index 483663e..a7af06b 100644
--- a/internal/web/server.go
+++ b/internal/web/server.go
@@ -66,9 +66,10 @@ func hostname(h string) string {
type ctxKey int
const (
- ctxUser ctxKey = iota
- ctxBlog // the blog a handler operates on (public page, or /b/{sub}/ management)
- ctxHostSub // subdomain derived from the Host header
+ ctxUser ctxKey = iota
+ ctxBlog // the blog a handler operates on (public page, or /b/{sub}/ management)
+ ctxBlogStore // that blog's store, bound to its own database
+ ctxHostSub // subdomain derived from the Host header
)
func currentUser(r *http.Request) *store.User {
@@ -81,13 +82,33 @@ func currentBlog(r *http.Request) *store.Blog {
return b
}
+// blogStore is the store of the blog in the context; only valid behind hostBlog or withBlog.
+func blogStore(r *http.Request) *store.BlogStore {
+ bs, _ := r.Context().Value(ctxBlogStore).(*store.BlogStore)
+ return bs
+}
+
// ---- middleware ----------------------------------------------------------
+// resolveBlog looks a subdomain up in the registry and opens its database.
+func (s *Server) resolveBlog(r *http.Request, sub string) (*http.Request, error) {
+ blog, err := s.st.BlogBySubdomain(r.Context(), sub)
+ if err != nil {
+ return r, err
+ }
+ bs, err := s.st.Open(r.Context(), blog)
+ if err != nil {
+ return r, err
+ }
+ ctx := context.WithValue(r.Context(), ctxBlog, blog)
+ return r.WithContext(context.WithValue(ctx, ctxBlogStore, bs)), nil
+}
+
// hostBlog resolves the blog named by the Host header into the context for public pages.
func (s *Server) hostBlog(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
sub, _ := r.Context().Value(ctxHostSub).(string)
- blog, err := s.st.BlogBySubdomain(r.Context(), sub)
+ r, err := s.resolveBlog(r, sub)
if err != nil {
if errors.Is(err, store.ErrNotFound) {
s.plainError(w, http.StatusNotFound, "No blog here (yet).")
@@ -96,7 +117,7 @@ func (s *Server) hostBlog(next http.HandlerFunc) http.HandlerFunc {
s.serverError(w, err)
return
}
- next(w, r.WithContext(context.WithValue(r.Context(), ctxBlog, blog)))
+ next(w, r)
}
}
@@ -176,7 +197,7 @@ func (s *Server) requireAdmin(next http.HandlerFunc) http.HandlerFunc {
func (s *Server) withBlog(next http.HandlerFunc) http.HandlerFunc {
return s.requireAuth(func(w http.ResponseWriter, r *http.Request) {
u := currentUser(r)
- blog, err := s.st.BlogBySubdomain(r.Context(), r.PathValue("sub"))
+ r, err := s.resolveBlog(r, r.PathValue("sub"))
if err != nil {
if errors.Is(err, store.ErrNotFound) {
http.NotFound(w, r)
@@ -185,11 +206,11 @@ func (s *Server) withBlog(next http.HandlerFunc) http.HandlerFunc {
s.serverError(w, err)
return
}
- if blog.OwnerID != u.ID && !u.IsSuperadmin() {
+ if blog := currentBlog(r); blog.OwnerID != u.ID && !u.IsSuperadmin() {
s.plainError(w, http.StatusForbidden, "This is not your blog.")
return
}
- next(w, r.WithContext(context.WithValue(r.Context(), ctxBlog, blog)))
+ next(w, r)
})
}