replace custom muxer with muxpatterns
@@ -5,16 +5,16 @@ <head>
<meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0"> - <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"> - <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"> - <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"> - <link rel='shortcut icon' href='/favicon.ico'> - <link rel="stylesheet" href="/style.css"> - <link rel="manifest" href="/manifest.json"> + <link rel="apple-touch-icon" sizes="180x180" href="/static/apple-touch-icon.png"> + <link rel="icon" type="image/png" sizes="32x32" href="/static/favicon-32x32.png"> + <link rel="icon" type="image/png" sizes="16x16" href="/static/favicon-16x16.png"> + <link rel='shortcut icon' href='/static/favicon.ico'> + <link rel="stylesheet" href="/static/style.css"> + <link rel="manifest" href="/static/manifest.json"> <script> if ('serviceWorker' in navigator) { - navigator.serviceWorker.register("/serviceworker.js"); + navigator.serviceWorker.register("/static/serviceworker.js"); } </script>
@@ -5,6 +5,7 @@
require ( github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 github.com/glebarez/go-sqlite v1.21.2 + github.com/jba/muxpatterns v0.3.0 golang.org/x/crypto v0.11.0 )@@ -13,6 +14,7 @@ github.com/dustin/go-humanize v1.0.1 // indirect
github.com/google/uuid v1.3.0 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + golang.org/x/exp v0.0.0-20230519143937-03e91628a987 // indirect golang.org/x/sys v0.10.0 // indirect modernc.org/libc v1.24.1 // indirect modernc.org/mathutil v1.6.0 // indirect
@@ -9,6 +9,8 @@ github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/jba/muxpatterns v0.3.0 h1:4mumR8LmA/7vUigN/BmUXtHXbwZOzggVuX9Dgqtw67c= +github.com/jba/muxpatterns v0.3.0/go.mod h1:77+op56At17SXLuQrR46FWJybINlMcj2E/KrDhS5JiY= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=@@ -22,6 +24,8 @@ golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/exp v0.0.0-20230519143937-03e91628a987 h1:3xJIFvzUFbu4ls0BTBYcgbCGhA63eAOEMxIHugyXJqA= +golang.org/x/exp v0.0.0-20230519143937-03e91628a987/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -3,20 +3,25 @@
import ( "log" "net/http" + + "github.com/jba/muxpatterns" ) func main() { s := New() - mux := http.NewServeMux() + mux := muxpatterns.NewServeMux() - // rootHandler handles /, /<username>, and 404 - mux.HandleFunc("/", s.rootHandler) - mux.HandleFunc("/discover", s.discoverHandler) - mux.HandleFunc("/feeds", s.settingsHandler) - mux.HandleFunc("/feeds/submit", s.feedsSubmitHandler) - mux.HandleFunc("/login", s.loginHandler) - mux.HandleFunc("/logout", s.logoutHandler) - mux.HandleFunc("/register", s.registerHandler) + mux.HandleFunc("GET /{$}", s.indexHandler) + mux.HandleFunc("GET /{username}", s.userHandler) + mux.HandleFunc("GET /static/{file}", s.staticHandler) + mux.HandleFunc("GET /discover", s.discoverHandler) + mux.HandleFunc("GET /feeds", s.settingsHandler) + mux.HandleFunc("POST /feeds/submit", s.feedsSubmitHandler) + mux.HandleFunc("GET /login", s.loginHandler) + mux.HandleFunc("POST /login", s.loginHandler) + mux.HandleFunc("GET /logout", s.logoutHandler) + mux.HandleFunc("POST /logout", s.logoutHandler) + mux.HandleFunc("POST /register", s.registerHandler) log.Println("main: listening on http://localhost:5544") log.Fatal(http.ListenAndServe(":5544", mux))
@@ -17,6 +17,7 @@ "git.j3s.sh/vore/lib"
"git.j3s.sh/vore/reaper" "git.j3s.sh/vore/rss" "git.j3s.sh/vore/sqlite" + "github.com/jba/muxpatterns" "golang.org/x/crypto/bcrypt" )@@ -43,40 +44,16 @@ }
return &s } -// rootHandler is our "wildcard handler", so in addition to -// serving /, it also acts as a router for a few arbitrary -// patterns that can't be registered at starttime -// this includes /<username>, static files, and 404 -func (s *Site) rootHandler(w http.ResponseWriter, r *http.Request) { - if r.URL.Path == "/" { - s.indexHandler(w, r) - return - } - - // path can be /<username> or /<static-file> - requestPath := strings.TrimPrefix(r.URL.Path, "/") - - // handles static files first - file := filepath.Join("files", "static", requestPath) +func (s *Site) staticHandler(w http.ResponseWriter, r *http.Request) { + file := filepath.Join("files", "static", muxpatterns.PathValue(r, "file")) if _, err := os.Stat(file); !errors.Is(err, os.ErrNotExist) { http.ServeFile(w, r, file) return } - - // handles /<username> - if s.db.UserExists(requestPath) { - s.userHandler(w, r) - return - } - - // 404 http.NotFound(w, r) } func (s *Site) indexHandler(w http.ResponseWriter, r *http.Request) { - if !s.methodAllowed(w, r, "GET") { - return - } if s.loggedIn(r) { http.Redirect(w, r, "/"+s.username(r), http.StatusSeeOther) return@@ -85,16 +62,10 @@ s.renderPage(w, r, "index", nil)
} func (s *Site) discoverHandler(w http.ResponseWriter, r *http.Request) { - if !s.methodAllowed(w, r, "GET") { - return - } s.renderPage(w, r, "discover", nil) } func (s *Site) loginHandler(w http.ResponseWriter, r *http.Request) { - if !s.methodAllowed(w, r, "GET", "POST") { - return - } if r.Method == "GET" { if s.loggedIn(r) { http.Redirect(w, r, "/", http.StatusSeeOther)@@ -117,9 +88,6 @@ }
// TODO: make this take a POST only in accordance w/ some spec func (s *Site) logoutHandler(w http.ResponseWriter, r *http.Request) { - if !s.methodAllowed(w, r, "GET", "POST") { - return - } http.SetCookie(w, &http.Cookie{ Name: "session_token", Value: "",@@ -128,9 +96,6 @@ http.Redirect(w, r, "/", http.StatusSeeOther)
} func (s *Site) registerHandler(w http.ResponseWriter, r *http.Request) { - if !s.methodAllowed(w, r, "POST") { - return - } username := r.FormValue("username") password := r.FormValue("password") err := s.register(username, password)@@ -147,11 +112,13 @@ http.Redirect(w, r, "/", http.StatusSeeOther)
} func (s *Site) userHandler(w http.ResponseWriter, r *http.Request) { - if !s.methodAllowed(w, r, "GET") { + username := muxpatterns.PathValue(r, "username") + + if !s.db.UserExists(username) { + http.NotFound(w, r) return } - username := strings.TrimPrefix(r.URL.Path, "/") items := s.reaper.SortFeedItemsByDate(s.reaper.GetUserFeeds(username)) data := struct { User string@@ -162,13 +129,9 @@ Items: items,
} s.renderPage(w, r, "user", data) - } func (s *Site) settingsHandler(w http.ResponseWriter, r *http.Request) { - if !s.methodAllowed(w, r, "GET") { - return - } if !s.loggedIn(r) { s.renderErr(w, "", http.StatusUnauthorized) return@@ -185,9 +148,6 @@ // show diff before submission (like tf plan)
// check if feed exists in db already? // validate that title exists func (s *Site) feedsSubmitHandler(w http.ResponseWriter, r *http.Request) { - if !s.methodAllowed(w, r, "POST") { - return - } if !s.loggedIn(r) { s.renderErr(w, "", http.StatusUnauthorized) return@@ -403,9 +363,6 @@ case http.StatusBadRequest:
prefix = "400 bad request\n" case http.StatusUnauthorized: prefix = "401 unauthorized\n" - case http.StatusMethodNotAllowed: - prefix = "405 method not allowed\n" - prefix += "request method: " case http.StatusInternalServerError: prefix = "(╥﹏╥) oopsie woopsie, uwu\n" prefix += "we made a fucky wucky (╥﹏╥)\n\n"@@ -413,24 +370,6 @@ prefix += "500 internal server error\n"
} log.Println(prefix + error) http.Error(w, prefix+error, code) -} - -// methodAllowed takes an http w/r, and returns true if the -// http requests method is in teh allowedMethods list. -// if methodNotAllowed returns false, it has already -// written a request & it's on the caller to close it. -func (s *Site) methodAllowed(w http.ResponseWriter, r *http.Request, allowedMethods ...string) bool { - allowed := false - for _, m := range allowedMethods { - if m == r.Method { - allowed = true - } - } - if allowed == false { - w.Header().Set("Allow", strings.Join(allowedMethods, ", ")) - s.renderErr(w, r.Method, http.StatusMethodNotAllowed) - } - return allowed } func (s *Site) randomCutePhrase() string {