From 0dac88fde8d7bfdffb7a4a23bd59552525786a16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9E=D0=BB=D0=B5=D0=B3=20=D0=91=D0=BE=D1=80=D0=BE=D0=B4?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Mon, 2 Feb 2026 17:26:45 +0200 Subject: [PATCH] router: added middlewares --- app/router/context.go | 2 ++ app/router/corsmw.go | 33 +++++++++++++++++++++++++++++++++ app/router/loggingmw.go | 27 +++++++++++++++++++++++++++ app/router/recovermw.go | 40 ++++++++++++++++++++++++++++++++++++++++ app/router/router.go | 13 +++++++++++-- 5 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 app/router/corsmw.go create mode 100644 app/router/loggingmw.go create mode 100644 app/router/recovermw.go diff --git a/app/router/context.go b/app/router/context.go index 51b7e10..783301e 100644 --- a/app/router/context.go +++ b/app/router/context.go @@ -11,6 +11,7 @@ type Context struct { Request *http.Request Writer http.ResponseWriter PathMap map[string]string + StatusCode int } func NewContext(writer http.ResponseWriter, request *http.Request) *Context { @@ -29,6 +30,7 @@ func (rctx *Context) SetHeader(key, value string) { } func (rctx *Context) SetStatus(httpStatus int) { + rctx.StatusCode = httpStatus rctx.Writer.WriteHeader(httpStatus) } diff --git a/app/router/corsmw.go b/app/router/corsmw.go new file mode 100644 index 0000000..ae0d830 --- /dev/null +++ b/app/router/corsmw.go @@ -0,0 +1,33 @@ +package router + +func NewCorsMiddleware() MiddlewareFunc { + mw := func(next Handler) Handler { + return newCorsHandler(next) + } + return mw +} + +type corsHandler struct { + next Handler +} + +func newCorsHandler(next Handler) *corsHandler { + return &corsHandler{ + next: next, + } +} + +func (hand corsHandler) ServeHTTP(ctx *Context) { + origin := ctx.Request.Header.Get("Origin") + if origin != "" { + ctx.SetHeader("Access-Control-Allow-Origin", origin) + ctx.SetHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE, PATCH") + ctx.SetHeader("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization") + ctx.SetHeader("Access-Control-Max-Age", "86400") + ctx.SetHeader("Access-Control-Allow-Credentials", "true") + } + if ctx.Request.Method == "OPTIONS" { + return + } + hand.next.ServeHTTP(ctx) +} diff --git a/app/router/loggingmw.go b/app/router/loggingmw.go new file mode 100644 index 0000000..0fe1416 --- /dev/null +++ b/app/router/loggingmw.go @@ -0,0 +1,27 @@ +package router + +func NewLoggingMiddleware(print func(string, ...any)) MiddlewareFunc { + mw := func(next Handler) Handler { + return newLoggingHandler(next, print) + } + return mw +} + +type loggingHandler struct { + next Handler + printFunc func(string, ...any) +} + +func newLoggingHandler(next Handler, print func(string, ...any)) *loggingHandler { + return &loggingHandler{ + next: next, + printFunc: print, + } +} + +func (logging loggingHandler) ServeHTTP(rctx *Context) { + logging.next.ServeHTTP(rctx) + logging.printFunc("%s %s %s %s %d", rctx.Request.RemoteAddr, + rctx.Request.Method, rctx.Request.URL.String(), + rctx.Request.Proto, rctx.StatusCode) +} diff --git a/app/router/recovermw.go b/app/router/recovermw.go new file mode 100644 index 0000000..6e135b6 --- /dev/null +++ b/app/router/recovermw.go @@ -0,0 +1,40 @@ +package router + +import ( + "net/http" + "runtime/debug" + "time" +) + +func NewRecoveryMiddleware(print func(string, ...any)) MiddlewareFunc { + mw := func(next Handler) Handler { + return newRecoveryHandler(next, print) + } + return mw +} + +type recoveryHandler struct { + next Handler + print func(string, ...any) +} + +func newRecoveryHandler(next Handler, print func(string, ...any)) *recoveryHandler { + return &recoveryHandler{ + next: next, + print: print, + } +} + +func (hand recoveryHandler) ServeHTTP(rctx *Context) { + exitFunc := func() { + err := recover() + if err != nil { + rctx.Writer.WriteHeader(http.StatusInternalServerError) + stack := string(debug.Stack()) + timestamp := time.Now().Format(time.RFC3339) + hand.print("%s %v ; %s\n", timestamp, err, stack) + } + } + defer exitFunc() + hand.next.ServeHTTP(rctx) +} diff --git a/app/router/router.go b/app/router/router.go index a446905..de2f620 100644 --- a/app/router/router.go +++ b/app/router/router.go @@ -6,6 +6,8 @@ import ( "regexp" ) +type MiddlewareFunc func(next Handler) Handler + type Handler interface { ServeHTTP(rctx *Context) } @@ -17,15 +19,22 @@ func (handlerFunc HandlerFunc) ServeHTTP(rctx *Context) { } type Router struct { + headHandler Handler routeHandler *Selector } func NewRouter() *Router { + selector := NewSelector() return &Router{ - routeHandler: NewSelector(), + routeHandler: selector, + headHandler: selector, } } +func (rout *Router) Use(mwFunc MiddlewareFunc) { + rout.headHandler = mwFunc(rout.headHandler) +} + func (rout *Router) Selector() *Selector { return rout.routeHandler } @@ -60,7 +69,7 @@ func (rout *Router) Delete(path string, handlerFunc HandlerFunc) { func (rout *Router) ServeHTTP(writer http.ResponseWriter, req *http.Request) { rctx := NewContext(writer, req) - rout.routeHandler.ServeHTTP(rctx) + rout.headHandler.ServeHTTP(rctx) } func (rout *Router) NotFound(handlerFunc HandlerFunc) {