diff --git a/app.go b/app.go index c2f30f9..465b8d1 100644 --- a/app.go +++ b/app.go @@ -5,13 +5,15 @@ import ( "crypto/tls" "errors" "fmt" - "github.com/loveuer/nf/internal/bytesconv" "io" "log" "net" "net/http" "path" "regexp" + "sync" + + "github.com/loveuer/nf/internal/bytesconv" ) var ( @@ -29,6 +31,8 @@ type App struct { trees methodTrees + pool *sync.Pool + maxParams uint16 maxSections uint16 @@ -40,13 +44,34 @@ type App struct { removeExtraSlash bool // false } +func (a *App) allocateContext() *Ctx { + var ( + skippedNodes = make([]skippedNode, 0, a.maxSections) + v = make(Params, 0, a.maxParams) + ) + + ctx := Ctx{ + lock: sync.Mutex{}, + app: a, + index: -1, + locals: make(map[string]any), + handlers: make([]HandlerFunc, 0), + skippedNodes: &skippedNodes, + params: &v, + } + + return &ctx +} + func (a *App) ServeHTTP(writer http.ResponseWriter, request *http.Request) { var ( err error - c = newContext(a, writer, request) + c = a.pool.Get().(*Ctx) nfe = new(Err) ) + c.reset(writer, request) + if err = c.verify(); err != nil { if errors.As(err, nfe) { _ = c.Status(nfe.Status).SendString(nfe.Msg) @@ -58,6 +83,8 @@ func (a *App) ServeHTTP(writer http.ResponseWriter, request *http.Request) { } a.handleHTTPRequest(c) + + a.pool.Put(c) } func (a *App) run(ln net.Listener) error { @@ -137,9 +164,7 @@ func (a *App) addRoute(method, path string, handlers ...HandlerFunc) { } func (a *App) handleHTTPRequest(c *Ctx) { - var ( - err error - ) + var err error httpMethod := c.Request.Method rPath := c.Request.URL.Path @@ -263,7 +288,7 @@ func redirectFixedPath(c *Ctx, root *node, trailingSlash bool) bool { func redirectRequest(c *Ctx) { req := c.Request - //rPath := req.URL.Path + // rPath := req.URL.Path rURL := req.URL.String() code := http.StatusMovedPermanently // Permanent redirect, request with GET method @@ -271,7 +296,7 @@ func redirectRequest(c *Ctx) { code = http.StatusTemporaryRedirect } - //debugPrint("redirecting request %d: %s --> %s", code, rPath, rURL) + // debugPrint("redirecting request %d: %s --> %s", code, rPath, rURL) http.Redirect(c.Writer, req, rURL, code) c.writermem.WriteHeaderNow() diff --git a/ctx.go b/ctx.go index 6133b76..2d40b81 100644 --- a/ctx.go +++ b/ctx.go @@ -6,8 +6,6 @@ import ( "encoding/json" "errors" "fmt" - "github.com/google/uuid" - "github.com/loveuer/nf/internal/sse" "html/template" "io" "mime/multipart" @@ -15,11 +13,12 @@ import ( "net/http" "strings" "sync" + + "github.com/google/uuid" + "github.com/loveuer/nf/internal/sse" ) -var ( - forwardHeaders = []string{"CF-Connecting-IP", "X-Forwarded-For", "X-Real-Ip"} -) +var forwardHeaders = []string{"CF-Connecting-IP", "X-Forwarded-For", "X-Real-Ip"} type Ctx struct { lock sync.Mutex @@ -39,45 +38,29 @@ type Ctx struct { fullPath string } -func newContext(app *App, writer http.ResponseWriter, request *http.Request) *Ctx { - - var ( - traceId string - skippedNodes = make([]skippedNode, 0, app.maxSections) - v = make(Params, 0, app.maxParams) - ) - - if traceId = request.Header.Get(TraceKey); traceId == "" { +func (c *Ctx) reset(w http.ResponseWriter, r *http.Request) { + traceId := r.Header.Get(TraceKey) + if traceId == "" { traceId = uuid.Must(uuid.NewV7()).String() } - c := context.WithValue(request.Context(), TraceKey, traceId) + c.writermem.reset(w) - ctx := &Ctx{ - lock: sync.Mutex{}, - Request: request.WithContext(c), - path: request.URL.Path, - method: request.Method, - StatusCode: 200, + c.Request = r.WithContext(context.WithValue(r.Context(), TraceKey, traceId)) + c.Writer = &c.writermem + c.handlers = nil + c.index = -1 + c.path = r.URL.Path + c.method = r.Method + c.StatusCode = 200 - app: app, - index: -1, - locals: map[string]interface{}{}, - handlers: make([]HandlerFunc, 0), - skippedNodes: &skippedNodes, - params: &v, + c.fullPath = "" + *c.params = (*c.params)[:0] + *c.skippedNodes = (*c.skippedNodes)[:0] + for key := range c.locals { + delete(c.locals, key) } - - ctx.writermem = responseWriter{ - ResponseWriter: writer, - size: -1, - status: 0, - } - - ctx.Writer = &ctx.writermem - ctx.writermem.Header().Set(TraceKey, traceId) - - return ctx + c.writermem.Header().Set(TraceKey, traceId) } func (c *Ctx) Locals(key string, value ...interface{}) interface{} { @@ -109,9 +92,7 @@ func (c *Ctx) Path(overWrite ...string) string { } func (c *Ctx) Cookies(key string, defaultValue ...string) string { - var ( - dv = "" - ) + dv := "" if len(defaultValue) > 0 { dv = defaultValue[0] diff --git a/nf.go b/nf.go index 3f701d5..2dfff39 100644 --- a/nf.go +++ b/nf.go @@ -1,5 +1,7 @@ package nf +import "sync" + const ( banner = " _ _ _ ___ _ \n | \\| |___| |_ | __|__ _ _ _ _ __| |\n | .` / _ \\ _| | _/ _ \\ || | ' \\/ _` |\n |_|\\_\\___/\\__| |_|\\___/\\_,_|_||_\\__,_|\n " _404 = "