Improve http router setup (use middlewares instead of custom functions)

This commit is contained in:
Jan-Lukas Else 2021-03-22 08:20:56 +01:00
parent 04f5cdc122
commit bbbabdb335
13 changed files with 567 additions and 604 deletions

View File

@ -4,8 +4,8 @@ import (
"net/http" "net/http"
) )
func serveBlogStats(blog, statsPath string) func(http.ResponseWriter, *http.Request) { func serveBlogStats(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) { blog := r.Context().Value(blogContextKey).(string)
// Build query // Build query
query, params := buildPostsQuery(&postsRequestConfig{ query, params := buildPostsQuery(&postsRequestConfig{
blog: blog, blog: blog,
@ -38,12 +38,11 @@ func serveBlogStats(blog, statsPath string) func(http.ResponseWriter, *http.Requ
} }
render(w, r, templateBlogStats, &renderData{ render(w, r, templateBlogStats, &renderData{
BlogString: blog, BlogString: blog,
Canonical: statsPath, Canonical: blogPath(blog) + appConfig.Blogs[blog].BlogStats.Path,
Data: map[string]interface{}{ Data: map[string]interface{}{
"total": totalCount, "total": totalCount,
"years": years, "years": years,
"counts": counts, "counts": counts,
}, },
}) })
}
} }

View File

@ -20,8 +20,7 @@ type comment struct {
Comment string Comment string
} }
func serveComment(blog string) func(http.ResponseWriter, *http.Request) { func serveComment(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
id, err := strconv.Atoi(chi.URLParam(r, "id")) id, err := strconv.Atoi(chi.URLParam(r, "id"))
if err != nil { if err != nil {
serveError(w, r, err.Error(), http.StatusBadRequest) serveError(w, r, err.Error(), http.StatusBadRequest)
@ -41,16 +40,15 @@ func serveComment(blog string) func(http.ResponseWriter, *http.Request) {
return return
} }
w.Header().Set("X-Robots-Tag", "noindex") w.Header().Set("X-Robots-Tag", "noindex")
blog := r.Context().Value(blogContextKey).(string)
render(w, r, templateComment, &renderData{ render(w, r, templateComment, &renderData{
BlogString: blog, BlogString: blog,
Canonical: appConfig.Server.PublicAddress + appConfig.Blogs[blog].getRelativePath(fmt.Sprintf("/comment/%d", id)), Canonical: appConfig.Server.PublicAddress + appConfig.Blogs[blog].getRelativePath(fmt.Sprintf("/comment/%d", id)),
Data: comment, Data: comment,
}) })
}
} }
func createComment(blog, commentsPath string) func(http.ResponseWriter, *http.Request) { func createComment(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
// Check target // Check target
target := checkCommentTarget(w, r) target := checkCommentTarget(w, r)
if target == "" { if target == "" {
@ -78,13 +76,12 @@ func createComment(blog, commentsPath string) func(http.ResponseWriter, *http.Re
// Serve error // Serve error
serveError(w, r, err.Error(), http.StatusInternalServerError) serveError(w, r, err.Error(), http.StatusInternalServerError)
} else { } else {
commentAddress := fmt.Sprintf("%s/%d", commentsPath, commentID) commentAddress := fmt.Sprintf("%s/%d", blogPath(r.Context().Value(blogContextKey).(string))+"/comment", commentID)
// Send webmention // Send webmention
_ = createWebmention(appConfig.Server.PublicAddress+commentAddress, appConfig.Server.PublicAddress+target) _ = createWebmention(appConfig.Server.PublicAddress+commentAddress, appConfig.Server.PublicAddress+target)
// Redirect to comment // Redirect to comment
http.Redirect(w, r, commentAddress, http.StatusFound) http.Redirect(w, r, commentAddress, http.StatusFound)
} }
}
} }
func checkCommentTarget(w http.ResponseWriter, r *http.Request) string { func checkCommentTarget(w http.ResponseWriter, r *http.Request) string {

View File

@ -33,8 +33,9 @@ func (p *commentsPaginationAdapter) Slice(offset, length int, data interface{})
return err return err
} }
func commentsAdmin(blog, commentPath string) func(http.ResponseWriter, *http.Request) { func commentsAdmin(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) { blog := r.Context().Value(blogContextKey).(string)
commentsPath := r.Context().Value(pathContextKey).(string)
// Adapter // Adapter
pageNoString := chi.URLParam(r, "page") pageNoString := chi.URLParam(r, "page")
pageNo, _ := strconv.Atoi(pageNoString) pageNo, _ := strconv.Atoi(pageNoString)
@ -57,9 +58,9 @@ func commentsAdmin(blog, commentPath string) func(http.ResponseWriter, *http.Req
prevPage, _ = p.Page() prevPage, _ = p.Page()
} }
if prevPage < 2 { if prevPage < 2 {
prevPath = commentPath prevPath = commentsPath
} else { } else {
prevPath = fmt.Sprintf("%s/page/%d", commentPath, prevPage) prevPath = fmt.Sprintf("%s/page/%d", commentsPath, prevPage)
} }
hasNext, _ = p.HasNext() hasNext, _ = p.HasNext()
if hasNext { if hasNext {
@ -67,7 +68,7 @@ func commentsAdmin(blog, commentPath string) func(http.ResponseWriter, *http.Req
} else { } else {
nextPage, _ = p.Page() nextPage, _ = p.Page()
} }
nextPath = fmt.Sprintf("%s/page/%d", commentPath, nextPage) nextPath = fmt.Sprintf("%s/page/%d", commentsPath, nextPage)
// Render // Render
render(w, r, templateCommentsAdmin, &renderData{ render(w, r, templateCommentsAdmin, &renderData{
BlogString: blog, BlogString: blog,
@ -79,7 +80,6 @@ func commentsAdmin(blog, commentPath string) func(http.ResponseWriter, *http.Req
"Next": slashIfEmpty(nextPath), "Next": slashIfEmpty(nextPath),
}, },
}) })
}
} }
func commentsAdminDelete(w http.ResponseWriter, r *http.Request) { func commentsAdminDelete(w http.ResponseWriter, r *http.Request) {

View File

@ -2,8 +2,10 @@ package main
import "net/http" import "net/http"
func serveCustomPage(blog *configBlog, page *customPage) func(http.ResponseWriter, *http.Request) { const customPageContextKey = "custompage"
return func(w http.ResponseWriter, r *http.Request) {
func serveCustomPage(w http.ResponseWriter, r *http.Request) {
page := r.Context().Value(customPageContextKey).(*customPage)
if appConfig.Cache != nil && appConfig.Cache.Enable && page.Cache { if appConfig.Cache != nil && appConfig.Cache.Enable && page.Cache {
if page.CacheExpiration != 0 { if page.CacheExpiration != 0 {
setInternalCacheExpirationHeader(w, page.CacheExpiration) setInternalCacheExpirationHeader(w, page.CacheExpiration)
@ -12,9 +14,8 @@ func serveCustomPage(blog *configBlog, page *customPage) func(http.ResponseWrite
} }
} }
render(w, r, page.Template, &renderData{ render(w, r, page.Template, &renderData{
Blog: blog, BlogString: r.Context().Value(blogContextKey).(string),
Canonical: appConfig.Server.PublicAddress + page.Path, Canonical: appConfig.Server.PublicAddress + page.Path,
Data: page.Data, Data: page.Data,
}) })
}
} }

View File

@ -11,19 +11,18 @@ import (
const editorPath = "/editor" const editorPath = "/editor"
func serveEditor(blog string) func(http.ResponseWriter, *http.Request) { func serveEditor(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) { blog := r.Context().Value(blogContextKey).(string)
render(w, r, templateEditor, &renderData{ render(w, r, templateEditor, &renderData{
BlogString: blog, BlogString: blog,
Data: map[string]interface{}{ Data: map[string]interface{}{
"Drafts": loadDrafts(blog), "Drafts": loadDrafts(blog),
}, },
}) })
}
} }
func serveEditorPost(blog string) func(w http.ResponseWriter, r *http.Request) { func serveEditorPost(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) { blog := r.Context().Value(blogContextKey).(string)
if action := r.FormValue("editoraction"); action != "" { if action := r.FormValue("editoraction"); action != "" {
switch action { switch action {
case "loadupdate": case "loadupdate":
@ -78,7 +77,6 @@ func serveEditorPost(blog string) func(w http.ResponseWriter, r *http.Request) {
return return
} }
editorMicropubPost(w, r, false) editorMicropubPost(w, r, false)
}
} }
func loadDrafts(blog string) []*post { func loadDrafts(blog string) []*post {

6
go.mod
View File

@ -44,7 +44,7 @@ require (
github.com/pquerna/otp v1.3.0 github.com/pquerna/otp v1.3.0
github.com/smartystreets/assertions v1.2.0 // indirect github.com/smartystreets/assertions v1.2.0 // indirect
github.com/snabb/sitemap v1.0.0 github.com/snabb/sitemap v1.0.0
github.com/spf13/afero v1.5.1 // indirect github.com/spf13/afero v1.6.0 // indirect
github.com/spf13/cast v1.3.1 github.com/spf13/cast v1.3.1
github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/viper v1.7.1 github.com/spf13/viper v1.7.1
@ -52,7 +52,7 @@ require (
github.com/thoas/go-funk v0.8.0 github.com/thoas/go-funk v0.8.0
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
github.com/vcraescu/go-paginator v1.0.1-0.20201114172518-2cfc59fe05c2 github.com/vcraescu/go-paginator v1.0.1-0.20201114172518-2cfc59fe05c2
github.com/yuin/goldmark v1.3.2 github.com/yuin/goldmark v1.3.3
github.com/yuin/goldmark-emoji v1.0.1 github.com/yuin/goldmark-emoji v1.0.1
go.uber.org/multierr v1.6.0 // indirect go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.16.0 // indirect go.uber.org/zap v1.16.0 // indirect
@ -61,7 +61,7 @@ require (
golang.org/x/mod v0.4.1 // indirect golang.org/x/mod v0.4.1 // indirect
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4 // indirect golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20210319071255-635bc2c9138d // indirect golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4 // indirect
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect
golang.org/x/text v0.3.5 // indirect golang.org/x/text v0.3.5 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect

12
go.sum
View File

@ -299,8 +299,8 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v0.0.0-20170901052352-ee1bd8ee15a1/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v0.0.0-20170901052352-ee1bd8ee15a1/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.5.1 h1:VHu76Lk0LSP1x254maIu2bplkWpfBWI+B+6fdoZprcg= github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
github.com/spf13/afero v1.5.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.1.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= github.com/spf13/cast v1.1.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
@ -340,8 +340,8 @@ github.com/vcraescu/go-paginator v1.0.1-0.20201114172518-2cfc59fe05c2 h1:l5j4nE6
github.com/vcraescu/go-paginator v1.0.1-0.20201114172518-2cfc59fe05c2/go.mod h1:NEDNuq1asYbAeX+uy6w56MDQSFmBQz9k+N9Hy6m4r2U= github.com/vcraescu/go-paginator v1.0.1-0.20201114172518-2cfc59fe05c2/go.mod h1:NEDNuq1asYbAeX+uy6w56MDQSFmBQz9k+N9Hy6m4r2U=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.2 h1:YjHC5TgyMmHpicTgEqDN0Q96Xo8K6tLXPnmNOHXCgs0= github.com/yuin/goldmark v1.3.3 h1:37BdQwPx8VOSic8eDSWee6QL9mRpZRm9VJp/QugNrW0=
github.com/yuin/goldmark v1.3.2/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.3/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark-emoji v1.0.1 h1:ctuWEyzGBwiucEqxzwe0SOYDXPAucOrE9NQC18Wa1os= github.com/yuin/goldmark-emoji v1.0.1 h1:ctuWEyzGBwiucEqxzwe0SOYDXPAucOrE9NQC18Wa1os=
github.com/yuin/goldmark-emoji v1.0.1/go.mod h1:2w1E6FEWLcDQkoTE+7HU6QF1F6SLlNGjRIBbIZQFqkQ= github.com/yuin/goldmark-emoji v1.0.1/go.mod h1:2w1E6FEWLcDQkoTE+7HU6QF1F6SLlNGjRIBbIZQFqkQ=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
@ -453,8 +453,8 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210319071255-635bc2c9138d h1:jbzgAvDZn8aEnytae+4ou0J0GwFZoHR0hOrTg4qH8GA= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4 h1:EZ2mChiOa8udjfp6rRmswTbtZN/QzUQp4ptM4rnjHvc=
golang.org/x/sys v0.0.0-20210319071255-635bc2c9138d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=

226
http.go
View File

@ -9,7 +9,6 @@ import (
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"time"
"github.com/caddyserver/certmagic" "github.com/caddyserver/certmagic"
"github.com/dchest/captcha" "github.com/dchest/captcha"
@ -110,6 +109,8 @@ var (
privateMode = false privateMode = false
privateModeHandler = []func(http.Handler) http.Handler{} privateModeHandler = []func(http.Handler) http.Handler{}
setBlogMiddlewares = map[string]func(http.Handler) http.Handler{}
captchaHandler http.Handler captchaHandler http.Handler
micropubRouter *chi.Mux micropubRouter *chi.Mux
@ -117,10 +118,9 @@ var (
webmentionsRouter *chi.Mux webmentionsRouter *chi.Mux
notificationsRouter *chi.Mux notificationsRouter *chi.Mux
activitypubRouter *chi.Mux activitypubRouter *chi.Mux
editorRouter *chi.Mux
editorRouters = map[string]*chi.Mux{} commentsRouter *chi.Mux
commentRouters = map[string]*chi.Mux{} searchRouter *chi.Mux
searchRouters = map[string]*chi.Mux{}
) )
func buildStaticHandlersRouters() error { func buildStaticHandlersRouters() error {
@ -157,9 +157,8 @@ func buildStaticHandlersRouters() error {
notificationsRouter = chi.NewRouter() notificationsRouter = chi.NewRouter()
notificationsRouter.Use(authMiddleware) notificationsRouter.Use(authMiddleware)
notificationsHandler := notificationsAdmin(notificationsPath) notificationsRouter.Get("/", notificationsAdmin)
notificationsRouter.Get("/", notificationsHandler) notificationsRouter.Get(paginationPath, notificationsAdmin)
notificationsRouter.Get(paginationPath, notificationsHandler)
if ap := appConfig.ActivityPub; ap != nil && ap.Enabled { if ap := appConfig.ActivityPub; ap != nil && ap.Enabled {
activitypubRouter = chi.NewRouter() activitypubRouter = chi.NewRouter()
@ -167,55 +166,42 @@ func buildStaticHandlersRouters() error {
activitypubRouter.Post("/{blog}/inbox", apHandleInbox) activitypubRouter.Post("/{blog}/inbox", apHandleInbox)
} }
for blog, blogConfig := range appConfig.Blogs { editorRouter = chi.NewRouter()
blogPath := blogPath(blogConfig)
editorRouter := chi.NewRouter()
editorRouter.Use(authMiddleware) editorRouter.Use(authMiddleware)
editorRouter.Get("/", serveEditor(blog)) editorRouter.Get("/", serveEditor)
editorRouter.Post("/", serveEditorPost(blog)) editorRouter.Post("/", serveEditorPost)
editorRouters[blog] = editorRouter
if commentsConfig := blogConfig.Comments; commentsConfig != nil && commentsConfig.Enabled { commentsRouter = chi.NewRouter()
commentsPath := blogPath + "/comment" commentsRouter.Use(privateModeHandler...)
commentRouter := chi.NewRouter() commentsRouter.With(cacheMiddleware).Get("/{id:[0-9]+}", serveComment)
commentRouter.Use(privateModeHandler...) commentsRouter.With(captchaMiddleware).Post("/", createComment)
commentRouter.With(cacheMiddleware).Get("/{id:[0-9]+}", serveComment(blog)) commentsRouter.Group(func(r chi.Router) {
commentRouter.With(captchaMiddleware).Post("/", createComment(blog, commentsPath))
// Admin // Admin
commentRouter.Group(func(r chi.Router) {
r.Use(authMiddleware) r.Use(authMiddleware)
handler := commentsAdmin(blog, commentsPath) r.Get("/", commentsAdmin)
r.Get("/", handler) r.Get(paginationPath, commentsAdmin)
r.Get(paginationPath, handler)
r.Post("/delete", commentsAdminDelete) r.Post("/delete", commentsAdminDelete)
}) })
commentRouters[blog] = commentRouter
}
if blogConfig.Search != nil && blogConfig.Search.Enabled { searchRouter = chi.NewRouter()
searchPath := blogPath + blogConfig.Search.Path
searchRouter := chi.NewRouter()
searchRouter.Use(privateModeHandler...) searchRouter.Use(privateModeHandler...)
searchRouter.Use(cacheMiddleware) searchRouter.Use(cacheMiddleware)
handler := serveSearch(blog, searchPath) searchRouter.Get("/", serveSearch)
searchRouter.Get("/", handler) searchRouter.Post("/", serveSearch)
searchRouter.Post("/", handler)
searchResultPath := "/" + searchPlaceholder searchResultPath := "/" + searchPlaceholder
resultHandler := serveSearchResults(blog, searchPath+searchResultPath) searchRouter.Get(searchResultPath, serveSearchResult)
searchRouter.Get(searchResultPath, resultHandler) searchRouter.Get(searchResultPath+feedPath, serveSearchResult)
searchRouter.Get(searchResultPath+feedPath, resultHandler) searchRouter.Get(searchResultPath+paginationPath, serveSearchResult)
searchRouter.Get(searchResultPath+paginationPath, resultHandler)
searchRouters[blog] = searchRouter for blog := range appConfig.Blogs {
} sbm := middleware.WithValue(blogContextKey, blog)
setBlogMiddlewares[blog] = sbm
} }
return nil return nil
} }
func buildDynamicRouter() (*chi.Mux, error) { func buildDynamicRouter() (*chi.Mux, error) {
startTime := time.Now()
r := chi.NewRouter() r := chi.NewRouter()
// Basic middleware // Basic middleware
@ -321,7 +307,9 @@ func buildDynamicRouter() (*chi.Mux, error) {
r.With(privateModeHandler...).With(cacheMiddleware).Get("/s/{id:[0-9a-fA-F]+}", redirectToLongPath) r.With(privateModeHandler...).With(cacheMiddleware).Get("/s/{id:[0-9a-fA-F]+}", redirectToLongPath)
for blog, blogConfig := range appConfig.Blogs { for blog, blogConfig := range appConfig.Blogs {
blogPath := blogPath(blogConfig) blogPath := blogPath(blog)
sbm := setBlogMiddlewares[blog]
// Sections // Sections
r.Group(func(r chi.Router) { r.Group(func(r chi.Router) {
@ -330,10 +318,15 @@ func buildDynamicRouter() (*chi.Mux, error) {
for _, section := range blogConfig.Sections { for _, section := range blogConfig.Sections {
if section.Name != "" { if section.Name != "" {
secPath := blogPath + "/" + section.Name secPath := blogPath + "/" + section.Name
handler := serveSection(blog, secPath, section) r.Group(func(r chi.Router) {
r.Get(secPath, handler) r.Use(sbm, middleware.WithValue(indexConfigKey, &indexConfig{
r.Get(secPath+feedPath, handler) path: secPath,
r.Get(secPath+paginationPath, handler) section: section,
}))
r.Get(secPath, serveIndex)
r.Get(secPath+feedPath, serveIndex)
r.Get(secPath+paginationPath, serveIndex)
})
} }
} }
}) })
@ -349,13 +342,19 @@ func buildDynamicRouter() (*chi.Mux, error) {
r.Group(func(r chi.Router) { r.Group(func(r chi.Router) {
r.Use(privateModeHandler...) r.Use(privateModeHandler...)
r.Use(cacheMiddleware) r.Use(cacheMiddleware)
r.Get(taxPath, serveTaxonomy(blog, taxonomy)) r.With(sbm, middleware.WithValue(taxonomyContextKey, taxonomy)).Get(taxPath, serveTaxonomy)
for _, tv := range taxValues { for _, tv := range taxValues {
vPath := taxPath + "/" + urlize(tv) vPath := taxPath + "/" + urlize(tv)
handler := serveTaxonomyValue(blog, vPath, taxonomy, tv) r.Group(func(r chi.Router) {
r.Get(vPath, handler) r.Use(sbm, middleware.WithValue(indexConfigKey, &indexConfig{
r.Get(vPath+feedPath, handler) path: vPath,
r.Get(vPath+paginationPath, handler) tax: taxonomy,
taxValue: tv,
}))
r.Get(vPath, serveIndex)
r.Get(vPath+feedPath, serveIndex)
r.Get(vPath+paginationPath, serveIndex)
})
} }
}) })
} }
@ -367,101 +366,74 @@ func buildDynamicRouter() (*chi.Mux, error) {
r.Use(privateModeHandler...) r.Use(privateModeHandler...)
r.Use(cacheMiddleware) r.Use(cacheMiddleware)
photoPath := blogPath + blogConfig.Photos.Path photoPath := blogPath + blogConfig.Photos.Path
handler := servePhotos(blog, photoPath) r.Use(sbm, middleware.WithValue(indexConfigKey, &indexConfig{
r.Get(photoPath, handler) path: photoPath,
r.Get(photoPath+feedPath, handler) parameter: blogConfig.Photos.Parameter,
r.Get(photoPath+paginationPath, handler) title: blogConfig.Photos.Title,
description: blogConfig.Photos.Description,
summaryTemplate: templatePhotosSummary,
}))
r.Get(photoPath, serveIndex)
r.Get(photoPath+feedPath, serveIndex)
r.Get(photoPath+paginationPath, serveIndex)
}) })
} }
// Search // Search
if blogConfig.Search != nil && blogConfig.Search.Enabled { if blogConfig.Search != nil && blogConfig.Search.Enabled {
r.Mount(blogPath+blogConfig.Search.Path, searchRouters[blog]) searchPath := blogPath + blogConfig.Search.Path
r.With(sbm, middleware.WithValue(pathContextKey, searchPath)).Mount(searchPath, searchRouter)
} }
// Stats // Stats
if blogConfig.BlogStats != nil && blogConfig.BlogStats.Enabled { if blogConfig.BlogStats != nil && blogConfig.BlogStats.Enabled {
statsPath := blogPath + blogConfig.BlogStats.Path statsPath := blogPath + blogConfig.BlogStats.Path
r.With(privateModeHandler...).With(cacheMiddleware).Get(statsPath, serveBlogStats(blog, statsPath)) r.With(privateModeHandler...).With(cacheMiddleware, sbm).Get(statsPath, serveBlogStats)
} }
// Year / month archives // Date archives
dates, err := allPublishedDates(blog)
if err != nil {
return nil, err
}
r.Group(func(r chi.Router) { r.Group(func(r chi.Router) {
r.Use(privateModeHandler...) r.Use(privateModeHandler...)
r.Use(cacheMiddleware) r.Use(cacheMiddleware, sbm)
already := map[string]bool{}
for _, d := range dates { yearRegex := `/{year:x|\d\d\d\d}`
// Year monthRegex := `/{month:x|\d\d}`
yearPath := blogPath + "/" + fmt.Sprintf("%0004d", d.year) dayRegex := `/{day:\d\d}`
if !already[yearPath] {
yearHandler := serveDate(blog, yearPath, d.year, 0, 0) yearPath := blogPath + yearRegex
r.Get(yearPath, yearHandler) r.Get(yearPath, serveDate)
r.Get(yearPath+feedPath, yearHandler) r.Get(yearPath+feedPath, serveDate)
r.Get(yearPath+paginationPath, yearHandler) r.Get(yearPath+paginationPath, serveDate)
already[yearPath] = true
} monthPath := yearPath + monthRegex
// Specific month r.Get(monthPath, serveDate)
monthPath := yearPath + "/" + fmt.Sprintf("%02d", d.month) r.Get(monthPath+feedPath, serveDate)
if !already[monthPath] { r.Get(monthPath+paginationPath, serveDate)
monthHandler := serveDate(blog, monthPath, d.year, d.month, 0)
r.Get(monthPath, monthHandler) dayPath := monthPath + dayRegex
r.Get(monthPath+feedPath, monthHandler) r.Get(dayPath, serveDate)
r.Get(monthPath+paginationPath, monthHandler) r.Get(dayPath+feedPath, serveDate)
already[monthPath] = true r.Get(dayPath+paginationPath, serveDate)
}
// Specific day
dayPath := monthPath + "/" + fmt.Sprintf("%02d", d.day)
if !already[dayPath] {
dayHandler := serveDate(blog, monthPath, d.year, d.month, d.day)
r.Get(dayPath, dayHandler)
r.Get(dayPath+feedPath, dayHandler)
r.Get(dayPath+paginationPath, dayHandler)
already[dayPath] = true
}
// Generic month
genericMonthPath := blogPath + "/x/" + fmt.Sprintf("%02d", d.month)
if !already[genericMonthPath] {
genericMonthHandler := serveDate(blog, genericMonthPath, 0, d.month, 0)
r.Get(genericMonthPath, genericMonthHandler)
r.Get(genericMonthPath+feedPath, genericMonthHandler)
r.Get(genericMonthPath+paginationPath, genericMonthHandler)
already[genericMonthPath] = true
}
// Specific day
genericMonthDayPath := genericMonthPath + "/" + fmt.Sprintf("%02d", d.day)
if !already[genericMonthDayPath] {
genericMonthDayHandler := serveDate(blog, genericMonthDayPath, 0, d.month, d.day)
r.Get(genericMonthDayPath, genericMonthDayHandler)
r.Get(genericMonthDayPath+feedPath, genericMonthDayHandler)
r.Get(genericMonthDayPath+paginationPath, genericMonthDayHandler)
already[genericMonthDayPath] = true
}
}
}) })
// Blog // Blog
if !blogConfig.PostAsHome { if !blogConfig.PostAsHome {
r.Group(func(r chi.Router) { r.Group(func(r chi.Router) {
r.Use(privateModeHandler...) r.Use(privateModeHandler...)
r.Use(cacheMiddleware) r.Use(cacheMiddleware, sbm)
handler := serveHome(blog, blogPath) r.Get(blogConfig.Path, serveHome)
r.Get(blogConfig.Path, handler) r.Get(blogConfig.Path+feedPath, serveHome)
r.Get(blogConfig.Path+feedPath, handler) r.Get(blogPath+paginationPath, serveHome)
r.Get(blogPath+paginationPath, handler)
}) })
} }
// Custom pages // Custom pages
for _, cp := range blogConfig.CustomPages { for _, cp := range blogConfig.CustomPages {
handler := serveCustomPage(blogConfig, cp) scp := middleware.WithValue(customPageContextKey, cp)
if cp.Cache { if cp.Cache {
r.With(privateModeHandler...).With(cacheMiddleware).Get(cp.Path, handler) r.With(privateModeHandler...).With(cacheMiddleware, sbm, scp).Get(cp.Path, serveCustomPage)
} else { } else {
r.With(privateModeHandler...).Get(cp.Path, handler) r.With(privateModeHandler...).With(sbm, scp).Get(cp.Path, serveCustomPage)
} }
} }
@ -471,15 +443,16 @@ func buildDynamicRouter() (*chi.Mux, error) {
if randomPath == "" { if randomPath == "" {
randomPath = "/random" randomPath = "/random"
} }
r.With(privateModeHandler...).Get(blogPath+randomPath, redirectToRandomPost(blog)) r.With(privateModeHandler...).With(sbm).Get(blogPath+randomPath, redirectToRandomPost)
} }
// Editor // Editor
r.Mount(blogPath+"/editor", editorRouters[blog]) r.With(sbm).Mount(blogPath+"/editor", editorRouter)
// Comments // Comments
if commentsConfig := blogConfig.Comments; commentsConfig != nil && commentsConfig.Enabled { if commentsConfig := blogConfig.Comments; commentsConfig != nil && commentsConfig.Enabled {
r.Mount(blogPath+"/comment", commentRouters[blog]) commentsPath := blogPath + "/comment"
r.With(sbm, middleware.WithValue(pathContextKey, commentsPath)).Mount(commentsPath, commentsRouter)
} }
} }
@ -500,19 +473,20 @@ func buildDynamicRouter() (*chi.Mux, error) {
serveError(rw, r, "", http.StatusMethodNotAllowed) serveError(rw, r, "", http.StatusMethodNotAllowed)
}) })
log.Println("Building handler took", time.Since(startTime))
return r, nil return r, nil
} }
func blogPath(cb *configBlog) string { func blogPath(blog string) string {
blogPath := cb.Path blogPath := appConfig.Blogs[blog].Path
if blogPath == "/" { if blogPath == "/" {
return "" return ""
} }
return blogPath return blogPath
} }
const blogContextKey requestContextKey = "blog"
const pathContextKey requestContextKey = "httpPath"
var cspDomains = "" var cspDomains = ""
func refreshCSPDomains() { func refreshCSPDomains() {

View File

@ -112,8 +112,7 @@ func (p *notificationsPaginationAdapter) Slice(offset, length int, data interfac
return err return err
} }
func notificationsAdmin(notificationPath string) func(http.ResponseWriter, *http.Request) { func notificationsAdmin(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
// Adapter // Adapter
pageNoString := chi.URLParam(r, "page") pageNoString := chi.URLParam(r, "page")
pageNo, _ := strconv.Atoi(pageNoString) pageNo, _ := strconv.Atoi(pageNoString)
@ -136,9 +135,9 @@ func notificationsAdmin(notificationPath string) func(http.ResponseWriter, *http
prevPage, _ = p.Page() prevPage, _ = p.Page()
} }
if prevPage < 2 { if prevPage < 2 {
prevPath = notificationPath prevPath = notificationsPath
} else { } else {
prevPath = fmt.Sprintf("%s/page/%d", notificationPath, prevPage) prevPath = fmt.Sprintf("%s/page/%d", notificationsPath, prevPage)
} }
hasNext, _ = p.HasNext() hasNext, _ = p.HasNext()
if hasNext { if hasNext {
@ -146,7 +145,7 @@ func notificationsAdmin(notificationPath string) func(http.ResponseWriter, *http
} else { } else {
nextPage, _ = p.Page() nextPage, _ = p.Page()
} }
nextPath = fmt.Sprintf("%s/page/%d", notificationPath, nextPage) nextPath = fmt.Sprintf("%s/page/%d", notificationsPath, nextPage)
// Render // Render
render(w, r, templateNotificationsAdmin, &renderData{ render(w, r, templateNotificationsAdmin, &renderData{
Data: map[string]interface{}{ Data: map[string]interface{}{
@ -157,5 +156,4 @@ func notificationsAdmin(notificationPath string) func(http.ResponseWriter, *http
"Next": slashIfEmpty(nextPath), "Next": slashIfEmpty(nextPath),
}, },
}) })
}
} }

113
posts.go
View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"html/template" "html/template"
@ -71,15 +72,13 @@ func servePost(w http.ResponseWriter, r *http.Request) {
}) })
} }
func redirectToRandomPost(blog string) func(http.ResponseWriter, *http.Request) { func redirectToRandomPost(rw http.ResponseWriter, r *http.Request) {
return func(rw http.ResponseWriter, r *http.Request) { randomPath, err := getRandomPostPath(r.Context().Value(blogContextKey).(string))
randomPath, err := getRandomPostPath(blog)
if err != nil { if err != nil {
serveError(rw, r, err.Error(), http.StatusInternalServerError) serveError(rw, r, err.Error(), http.StatusInternalServerError)
return return
} }
http.Redirect(rw, r, randomPath, http.StatusFound) http.Redirect(rw, r, randomPath, http.StatusFound)
}
} }
type postPaginationAdapter struct { type postPaginationAdapter struct {
@ -105,77 +104,60 @@ func (p *postPaginationAdapter) Slice(offset, length int, data interface{}) erro
return err return err
} }
func serveHome(blog string, path string) func(w http.ResponseWriter, r *http.Request) { func serveHome(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) { blog := r.Context().Value(blogContextKey).(string)
if asRequest, ok := r.Context().Value(asRequestKey).(bool); ok && asRequest { if asRequest, ok := r.Context().Value(asRequestKey).(bool); ok && asRequest {
appConfig.Blogs[blog].serveActivityStreams(blog, w, r) appConfig.Blogs[blog].serveActivityStreams(blog, w, r)
return return
} }
serveIndex(&indexConfig{ serveIndex(w, r.WithContext(context.WithValue(r.Context(), indexConfigKey, &indexConfig{
blog: blog, path: blogPath(blog),
path: path, })))
})(w, r) }
func serveDate(w http.ResponseWriter, r *http.Request) {
var year, month, day int
if ys := chi.URLParam(r, "year"); ys != "" && ys != "x" {
year, _ = strconv.Atoi(ys)
} }
} if ms := chi.URLParam(r, "month"); ms != "" && ms != "x" {
month, _ = strconv.Atoi(ms)
func serveSection(blog string, path string, section *section) func(w http.ResponseWriter, r *http.Request) { }
return serveIndex(&indexConfig{ if ds := chi.URLParam(r, "day"); ds != "" {
blog: blog, day, _ = strconv.Atoi(ds)
path: path, }
section: section, if year == 0 && month == 0 && day == 0 {
}) serve404(w, r)
} return
}
func serveTaxonomyValue(blog string, path string, tax *taxonomy, value string) func(w http.ResponseWriter, r *http.Request) { var title, dPath strings.Builder
return serveIndex(&indexConfig{ dPath.WriteString(blogPath(r.Context().Value(blogContextKey).(string)) + "/")
blog: blog,
path: path,
tax: tax,
taxValue: value,
})
}
func servePhotos(blog string, path string) func(w http.ResponseWriter, r *http.Request) {
return serveIndex(&indexConfig{
blog: blog,
path: path,
parameter: appConfig.Blogs[blog].Photos.Parameter,
title: appConfig.Blogs[blog].Photos.Title,
description: appConfig.Blogs[blog].Photos.Description,
summaryTemplate: templatePhotosSummary,
})
}
func serveSearchResults(blog string, path string) func(w http.ResponseWriter, r *http.Request) {
return serveIndex(&indexConfig{
blog: blog,
path: path,
})
}
func serveDate(blog string, path string, year, month, day int) func(w http.ResponseWriter, r *http.Request) {
var title strings.Builder
if year != 0 { if year != 0 {
title.WriteString(fmt.Sprintf("%0004d", year)) ys := fmt.Sprintf("%0004d", year)
title.WriteString(ys)
dPath.WriteString(ys)
} else { } else {
title.WriteString("XXXX") title.WriteString("XXXX")
dPath.WriteString("x")
} }
if month != 0 { if month != 0 {
title.WriteString(fmt.Sprintf("-%02d", month)) title.WriteString(fmt.Sprintf("-%02d", month))
dPath.WriteString(fmt.Sprintf("/%02d", month))
} else if day != 0 { } else if day != 0 {
title.WriteString("-XX") title.WriteString("-XX")
dPath.WriteString("/x")
} }
if day != 0 { if day != 0 {
title.WriteString(fmt.Sprintf("-%02d", day)) title.WriteString(fmt.Sprintf("-%02d", day))
dPath.WriteString(fmt.Sprintf("/%02d", day))
} }
return serveIndex(&indexConfig{ serveIndex(w, r.WithContext(context.WithValue(r.Context(), indexConfigKey, &indexConfig{
blog: blog, path: dPath.String(),
path: path,
year: year, year: year,
month: month, month: month,
day: day, day: day,
title: title.String(), title: title.String(),
}) })))
} }
type indexConfig struct { type indexConfig struct {
@ -191,8 +173,14 @@ type indexConfig struct {
summaryTemplate string summaryTemplate string
} }
func serveIndex(ic *indexConfig) func(w http.ResponseWriter, r *http.Request) { const indexConfigKey requestContextKey = "indexConfig"
return func(w http.ResponseWriter, r *http.Request) {
func serveIndex(w http.ResponseWriter, r *http.Request) {
ic := r.Context().Value(indexConfigKey).(*indexConfig)
blog := ic.blog
if blog == "" {
blog, _ = r.Context().Value(blogContextKey).(string)
}
search := chi.URLParam(r, "search") search := chi.URLParam(r, "search")
if search != "" { if search != "" {
search = searchDecode(search) search = searchDecode(search)
@ -203,12 +191,12 @@ func serveIndex(ic *indexConfig) func(w http.ResponseWriter, r *http.Request) {
if ic.section != nil { if ic.section != nil {
sections = []string{ic.section.Name} sections = []string{ic.section.Name}
} else { } else {
for sectionKey := range appConfig.Blogs[ic.blog].Sections { for sectionKey := range appConfig.Blogs[blog].Sections {
sections = append(sections, sectionKey) sections = append(sections, sectionKey)
} }
} }
p := paginator.New(&postPaginationAdapter{config: &postsRequestConfig{ p := paginator.New(&postPaginationAdapter{config: &postsRequestConfig{
blog: ic.blog, blog: blog,
sections: sections, sections: sections,
taxonomy: ic.tax, taxonomy: ic.tax,
taxonomyValue: ic.taxValue, taxonomyValue: ic.taxValue,
@ -218,7 +206,7 @@ func serveIndex(ic *indexConfig) func(w http.ResponseWriter, r *http.Request) {
publishedMonth: ic.month, publishedMonth: ic.month,
publishedDay: ic.day, publishedDay: ic.day,
status: statusPublished, status: statusPublished,
}}, appConfig.Blogs[ic.blog].Pagination) }}, appConfig.Blogs[blog].Pagination)
p.SetPage(pageNo) p.SetPage(pageNo)
var posts []*post var posts []*post
t := servertiming.FromContext(r.Context()).NewMetric("gp").Start() t := servertiming.FromContext(r.Context()).NewMetric("gp").Start()
@ -237,13 +225,13 @@ func serveIndex(ic *indexConfig) func(w http.ResponseWriter, r *http.Request) {
title = ic.section.Title title = ic.section.Title
description = ic.section.Description description = ic.section.Description
} else if search != "" { } else if search != "" {
title = fmt.Sprintf("%s: %s", appConfig.Blogs[ic.blog].Search.Title, search) title = fmt.Sprintf("%s: %s", appConfig.Blogs[blog].Search.Title, search)
} }
// Clean title // Clean title
title = bluemonday.StrictPolicy().Sanitize(title) title = bluemonday.StrictPolicy().Sanitize(title)
// Check if feed // Check if feed
if ft := feedType(chi.URLParam(r, "feed")); ft != noFeed { if ft := feedType(chi.URLParam(r, "feed")); ft != noFeed {
generateFeed(ic.blog, ft, w, r, posts, title, description) generateFeed(blog, ft, w, r, posts, title, description)
return return
} }
// Path // Path
@ -278,7 +266,7 @@ func serveIndex(ic *indexConfig) func(w http.ResponseWriter, r *http.Request) {
summaryTemplate = templateSummary summaryTemplate = templateSummary
} }
render(w, r, templateIndex, &renderData{ render(w, r, templateIndex, &renderData{
BlogString: ic.blog, BlogString: blog,
Canonical: appConfig.Server.PublicAddress + path, Canonical: appConfig.Server.PublicAddress + path,
Data: map[string]interface{}{ Data: map[string]interface{}{
"Title": title, "Title": title,
@ -292,5 +280,4 @@ func serveIndex(ic *indexConfig) func(w http.ResponseWriter, r *http.Request) {
"SummaryTemplate": summaryTemplate, "SummaryTemplate": summaryTemplate,
}, },
}) })
}
} }

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"context"
"encoding/base64" "encoding/base64"
"net/http" "net/http"
"net/url" "net/url"
@ -10,8 +11,9 @@ import (
const searchPlaceholder = "{search}" const searchPlaceholder = "{search}"
func serveSearch(blog string, servePath string) func(w http.ResponseWriter, r *http.Request) { func serveSearch(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) { blog := r.Context().Value(blogContextKey).(string)
servePath := r.Context().Value(pathContextKey).(string)
err := r.ParseForm() err := r.ParseForm()
if err != nil { if err != nil {
serveError(w, r, err.Error(), http.StatusBadRequest) serveError(w, r, err.Error(), http.StatusBadRequest)
@ -25,7 +27,12 @@ func serveSearch(blog string, servePath string) func(w http.ResponseWriter, r *h
BlogString: blog, BlogString: blog,
Canonical: appConfig.Server.PublicAddress + servePath, Canonical: appConfig.Server.PublicAddress + servePath,
}) })
} }
func serveSearchResult(w http.ResponseWriter, r *http.Request) {
serveIndex(w, r.WithContext(context.WithValue(r.Context(), indexConfigKey, &indexConfig{
path: r.Context().Value(pathContextKey).(string) + "/" + searchPlaceholder,
})))
} }
func searchEncode(search string) string { func searchEncode(search string) string {

View File

@ -2,8 +2,11 @@ package main
import "net/http" import "net/http"
func serveTaxonomy(blog string, tax *taxonomy) func(w http.ResponseWriter, r *http.Request) { const taxonomyContextKey = "taxonomy"
return func(w http.ResponseWriter, r *http.Request) {
func serveTaxonomy(w http.ResponseWriter, r *http.Request) {
blog := r.Context().Value(blogContextKey).(string)
tax := r.Context().Value(taxonomyContextKey).(*taxonomy)
allValues, err := allTaxonomyValues(blog, tax.Name) allValues, err := allTaxonomyValues(blog, tax.Name)
if err != nil { if err != nil {
serveError(w, r, err.Error(), http.StatusInternalServerError) serveError(w, r, err.Error(), http.StatusInternalServerError)
@ -17,5 +20,4 @@ func serveTaxonomy(blog string, tax *taxonomy) func(w http.ResponseWriter, r *ht
"ValueGroups": groupStrings(allValues), "ValueGroups": groupStrings(allValues),
}, },
}) })
}
} }

4
tor.go
View File

@ -41,7 +41,7 @@ func startOnionService(h http.Handler) error {
return err return err
} }
pemEncoded := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: x509Encoded}) pemEncoded := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: x509Encoded})
os.WriteFile(torKeyPath, pemEncoded, os.ModePerm) _ = os.WriteFile(torKeyPath, pemEncoded, os.ModePerm)
} else { } else {
d, _ := os.ReadFile(torKeyPath) d, _ := os.ReadFile(torKeyPath)
block, _ := pem.Decode(d) block, _ := pem.Decode(d)
@ -53,7 +53,7 @@ func startOnionService(h http.Handler) error {
} }
// Start tor with default config (can set start conf's DebugWriter to os.Stdout for debug logs) // Start tor with default config (can set start conf's DebugWriter to os.Stdout for debug logs)
log.Println("Starting and registering onion service, please wait a couple of minutes...") log.Println("Starting and registering onion service, please wait a couple of minutes...")
t, err := tor.Start(nil, &tor.StartConf{ t, err := tor.Start(context.Background(), &tor.StartConf{
TempDataDirBase: os.TempDir(), TempDataDirBase: os.TempDir(),
}) })
if err != nil { if err != nil {