From 92ff3714ad04f35dcaf07fdd12b38b238bad0f89 Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Sun, 27 Apr 2014 21:13:35 +0100 Subject: [PATCH] Clean up routing --- mailhog/http/api/v1.go | 33 +++++++------- mailhog/http/handler/regexp.go | 55 ----------------------- mailhog/http/router/regexp.go | 79 ++++++++++++++++++++++++++++++++++ mailhog/http/server.go | 30 ++++++------- 4 files changed, 111 insertions(+), 86 deletions(-) delete mode 100644 mailhog/http/handler/regexp.go create mode 100644 mailhog/http/router/regexp.go diff --git a/mailhog/http/api/v1.go b/mailhog/http/api/v1.go index 0c8b270..fb0971c 100644 --- a/mailhog/http/api/v1.go +++ b/mailhog/http/api/v1.go @@ -5,12 +5,11 @@ import ( "encoding/json" "net/http" "net/smtp" - "regexp" "strconv" "github.com/ian-kent/MailHog/mailhog/data" "github.com/ian-kent/MailHog/mailhog/config" "github.com/ian-kent/MailHog/mailhog/storage" - "github.com/ian-kent/MailHog/mailhog/http/handler" + "github.com/ian-kent/MailHog/mailhog/http/router" ) type APIv1 struct { @@ -33,18 +32,20 @@ func CreateAPIv1(exitCh chan int, conf *config.Config, server *http.Server) *API server: server, } - server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"GET"},regexp.MustCompile("^/api/v1/messages/?$"), apiv1.messages) - server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"DELETE"},regexp.MustCompile("^/api/v1/messages/?$"), apiv1.delete_all) - server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"GET"},regexp.MustCompile("^/api/v1/messages/([0-9a-f]+)/?$"), apiv1.message) - server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"DELETE"},regexp.MustCompile("^/api/v1/messages/([0-9a-f]+)/?$"), apiv1.delete_one) - server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"GET"},regexp.MustCompile("^/api/v1/messages/([0-9a-f]+)/download/?$"), apiv1.download) - server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"GET"},regexp.MustCompile("^/api/v1/messages/([0-9a-f]+)/mime/part/(\\d+)/download/?$"), apiv1.download_part) - server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"POST"},regexp.MustCompile("^/api/v1/messages/([0-9a-f]+)/release/?$"), apiv1.release_one) + r := server.Handler.(*router.Router) + + r.Get("^/api/v1/messages/?$", apiv1.messages) + r.Delete("^/api/v1/messages/?$", apiv1.delete_all) + r.Get("^/api/v1/messages/([0-9a-f]+)/?$", apiv1.message) + r.Delete("^/api/v1/messages/([0-9a-f]+)/?$", apiv1.delete_one) + r.Get("^/api/v1/messages/([0-9a-f]+)/download/?$", apiv1.download) + r.Get("^/api/v1/messages/([0-9a-f]+)/mime/part/(\\d+)/download/?$", apiv1.download_part) + r.Post("^/api/v1/messages/([0-9a-f]+)/release/?$", apiv1.release_one) return apiv1 } -func (apiv1 *APIv1) messages(w http.ResponseWriter, r *http.Request, route *handler.Route) { +func (apiv1 *APIv1) messages(w http.ResponseWriter, r *http.Request, route *router.Route) { log.Println("[APIv1] GET /api/v1/messages") // TODO start, limit @@ -64,7 +65,7 @@ func (apiv1 *APIv1) messages(w http.ResponseWriter, r *http.Request, route *hand } } -func (apiv1 *APIv1) message(w http.ResponseWriter, r *http.Request, route *handler.Route) { +func (apiv1 *APIv1) message(w http.ResponseWriter, r *http.Request, route *router.Route) { match := route.Pattern.FindStringSubmatch(r.URL.Path) id := match[1] @@ -86,7 +87,7 @@ func (apiv1 *APIv1) message(w http.ResponseWriter, r *http.Request, route *handl } } -func (apiv1 *APIv1) download(w http.ResponseWriter, r *http.Request, route *handler.Route) { +func (apiv1 *APIv1) download(w http.ResponseWriter, r *http.Request, route *router.Route) { match := route.Pattern.FindStringSubmatch(r.URL.Path) id := match[1] log.Printf("[APIv1] GET /api/v1/messages/%s/download\n", id) @@ -116,7 +117,7 @@ func (apiv1 *APIv1) download(w http.ResponseWriter, r *http.Request, route *hand } } -func (apiv1 *APIv1) download_part(w http.ResponseWriter, r *http.Request, route *handler.Route) { +func (apiv1 *APIv1) download_part(w http.ResponseWriter, r *http.Request, route *router.Route) { match := route.Pattern.FindStringSubmatch(r.URL.Path) id := match[1] part, _ := strconv.Atoi(match[2]) @@ -148,7 +149,7 @@ func (apiv1 *APIv1) download_part(w http.ResponseWriter, r *http.Request, route } } -func (apiv1 *APIv1) delete_all(w http.ResponseWriter, r *http.Request, route *handler.Route) { +func (apiv1 *APIv1) delete_all(w http.ResponseWriter, r *http.Request, route *router.Route) { log.Println("[APIv1] POST /api/v1/messages") w.Header().Set("Content-Type", "text/json") @@ -162,7 +163,7 @@ func (apiv1 *APIv1) delete_all(w http.ResponseWriter, r *http.Request, route *ha } } -func (apiv1 *APIv1) release_one(w http.ResponseWriter, r *http.Request, route *handler.Route) { +func (apiv1 *APIv1) release_one(w http.ResponseWriter, r *http.Request, route *router.Route) { match := route.Pattern.FindStringSubmatch(r.URL.Path) id := match[1] log.Printf("[APIv1] POST /api/v1/messages/%s/release\n", id) @@ -208,7 +209,7 @@ func (apiv1 *APIv1) release_one(w http.ResponseWriter, r *http.Request, route *h log.Printf("Message released successfully") } -func (apiv1 *APIv1) delete_one(w http.ResponseWriter, r *http.Request, route *handler.Route) { +func (apiv1 *APIv1) delete_one(w http.ResponseWriter, r *http.Request, route *router.Route) { match := route.Pattern.FindStringSubmatch(r.URL.Path) id := match[1] log.Printf("[APIv1] POST /api/v1/messages/%s/delete\n", id) diff --git a/mailhog/http/handler/regexp.go b/mailhog/http/handler/regexp.go deleted file mode 100644 index a5e6cda..0000000 --- a/mailhog/http/handler/regexp.go +++ /dev/null @@ -1,55 +0,0 @@ -package handler; - -import ( - "regexp" - "net/http" -) - -// http://stackoverflow.com/questions/6564558/wildcards-in-the-pattern-for-http-handlefunc - -type Route struct { - Methods map[string]int - Pattern *regexp.Regexp - Handler HandlerFunc -} - -type HandlerFunc func(http.ResponseWriter, *http.Request, *Route) - -//type Handler http.Handler -func (f HandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request, route *Route) { - f(w, r, route) -} - -type RegexpHandler struct { - routes []*Route -} - -func (h *RegexpHandler) Handler(methods []string, pattern *regexp.Regexp, handler HandlerFunc) { - m := make(map[string]int,0) - for _, v := range methods { - m[v] = 1 - } - h.routes = append(h.routes, &Route{m, pattern, handler}) -} - -func (h *RegexpHandler) HandleFunc(methods []string, pattern *regexp.Regexp, handler func(http.ResponseWriter, *http.Request, *Route)) { - m := make(map[string]int,0) - for _, v := range methods { - m[v] = 1 - } - h.routes = append(h.routes, &Route{m, pattern, HandlerFunc(handler)}) -} - -func (h *RegexpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - for _, route := range h.routes { - if route.Pattern.MatchString(r.URL.Path) { - _, ok := route.Methods[r.Method] - if ok { - route.Handler.ServeHTTP(w, r, route) - return - } - } - } - // no pattern matched; send 404 response - http.NotFound(w, r) -} diff --git a/mailhog/http/router/regexp.go b/mailhog/http/router/regexp.go new file mode 100644 index 0000000..dcf06c2 --- /dev/null +++ b/mailhog/http/router/regexp.go @@ -0,0 +1,79 @@ +package router; + +import ( + "regexp" + "net/http" +) + +// http://stackoverflow.com/questions/6564558/wildcards-in-the-pattern-for-http-handlefunc + +type Route struct { + Methods map[string]int + Pattern *regexp.Regexp + Handler HandlerFunc +} + +type HandlerFunc func(http.ResponseWriter, *http.Request, *Route) + +//type Handler http.Handler +func (f HandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request, route *Route) { + f(w, r, route) +} + +type Router struct { + routes []*Route +} + +func (h *Router) Get(pattern string, handler HandlerFunc) { + h.Handler([]string{"GET"}, regexp.MustCompile(pattern), handler) +} + +func (h *Router) Post(pattern string, handler HandlerFunc) { + h.Handler([]string{"POST"}, regexp.MustCompile(pattern), handler) +} + +func (h *Router) Put(pattern string, handler HandlerFunc) { + h.Handler([]string{"PUT"}, regexp.MustCompile(pattern), handler) +} + +func (h *Router) Delete(pattern string, handler HandlerFunc) { + h.Handler([]string{"DELETE"}, regexp.MustCompile(pattern), handler) +} + +func (h *Router) Patch(pattern string, handler HandlerFunc) { + h.Handler([]string{"PATCH"}, regexp.MustCompile(pattern), handler) +} + +func (h *Router) Options(pattern string, handler HandlerFunc) { + h.Handler([]string{"OPTIONS"}, regexp.MustCompile(pattern), handler) +} + +func (h *Router) Handler(methods []string, pattern *regexp.Regexp, handler HandlerFunc) { + m := make(map[string]int,0) + for _, v := range methods { + m[v] = 1 + } + h.routes = append(h.routes, &Route{m, pattern, handler}) +} + +func (h *Router) HandleFunc(methods []string, pattern *regexp.Regexp, handler func(http.ResponseWriter, *http.Request, *Route)) { + m := make(map[string]int,0) + for _, v := range methods { + m[v] = 1 + } + h.routes = append(h.routes, &Route{m, pattern, HandlerFunc(handler)}) +} + +func (h *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) { + for _, route := range h.routes { + if route.Pattern.MatchString(r.URL.Path) { + _, ok := route.Methods[r.Method] + if ok { + route.Handler.ServeHTTP(w, r, route) + return + } + } + } + // no pattern matched; send 404 response + http.NotFound(w, r) +} diff --git a/mailhog/http/server.go b/mailhog/http/server.go index 74d8a0d..6ab860f 100644 --- a/mailhog/http/server.go +++ b/mailhog/http/server.go @@ -1,12 +1,11 @@ package http import ( - "regexp" "net/http" "strings" "github.com/ian-kent/MailHog/mailhog/config" "github.com/ian-kent/MailHog/mailhog/http/api" - "github.com/ian-kent/MailHog/mailhog/http/handler" + "github.com/ian-kent/MailHog/mailhog/http/router" ) var exitChannel chan int @@ -14,37 +13,37 @@ var cfg *config.Config // TODO clean this mess up -func web_exit(w http.ResponseWriter, r *http.Request, route *handler.Route) { +func web_exit(w http.ResponseWriter, r *http.Request, route *router.Route) { web_headers(w) w.Write([]byte("Exiting MailHog!")) exitChannel <- 1 } -func web_index(w http.ResponseWriter, r *http.Request, route *handler.Route) { +func web_index(w http.ResponseWriter, r *http.Request, route *router.Route) { web_headers(w) data, _ := cfg.Assets("assets/templates/index.html") w.Write([]byte(web_render(string(data)))) } -func web_jscontroller(w http.ResponseWriter, r *http.Request, route *handler.Route) { +func web_jscontroller(w http.ResponseWriter, r *http.Request, route *router.Route) { w.Header().Set("Content-Type", "text/javascript") data, _ := cfg.Assets("assets/js/controllers.js") w.Write(data) } -func web_imgcontroller(w http.ResponseWriter, r *http.Request, route *handler.Route) { +func web_imgcontroller(w http.ResponseWriter, r *http.Request, route *router.Route) { w.Header().Set("Content-Type", "image/png") data, _ := cfg.Assets("assets/images/hog.png") w.Write(data) } -func web_img_github(w http.ResponseWriter, r *http.Request, route *handler.Route) { +func web_img_github(w http.ResponseWriter, r *http.Request, route *router.Route) { w.Header().Set("Content-Type", "image/png") data, _ := cfg.Assets("assets/images/github.png") w.Write(data) } -func web_img_ajaxloader(w http.ResponseWriter, r *http.Request, route *handler.Route) { +func web_img_ajaxloader(w http.ResponseWriter, r *http.Request, route *router.Route) { w.Header().Set("Content-Type", "image/gif") data, _ := cfg.Assets("assets/images/ajax-loader.gif") w.Write(data) @@ -67,17 +66,18 @@ func Start(exitCh chan int, conf *config.Config) { exitChannel = exitCh cfg = conf + r := &router.Router{} server := &http.Server{ Addr: conf.HTTPBindAddr, - Handler: &handler.RegexpHandler{}, + Handler: r, } - server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"GET"},regexp.MustCompile("^/exit/?$"), web_exit) - server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"GET"},regexp.MustCompile("^/js/controllers.js$"), web_jscontroller) - server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"GET"},regexp.MustCompile("^/images/hog.png$"), web_imgcontroller) - server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"GET"},regexp.MustCompile("^/images/github.png$"), web_img_github) - server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"GET"},regexp.MustCompile("^/images/ajax-loader.gif$"), web_img_ajaxloader) - server.Handler.(*handler.RegexpHandler).HandleFunc([]string{"GET"},regexp.MustCompile("^/$"), web_index) + r.Get("^/exit/?$", web_exit) + r.Get("^/js/controllers.js$", web_jscontroller) + r.Get("^/images/hog.png$", web_imgcontroller) + r.Get("^/images/github.png$", web_img_github) + r.Get("^/images/ajax-loader.gif$", web_img_ajaxloader) + r.Get("^/$", web_index) api.CreateAPIv1(exitCh, conf, server)