Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
366517de18 |
169
DOCS.md
Normal file
169
DOCS.md
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
# Documentation
|
||||||
|
|
||||||
|
## Core Types
|
||||||
|
|
||||||
|
### Router
|
||||||
|
|
||||||
|
Main router that implements fasthttp handler.
|
||||||
|
|
||||||
|
```go
|
||||||
|
router := router.New()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Handler
|
||||||
|
|
||||||
|
Request handler function type.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Handler func(ctx Ctx, params []string)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Middleware
|
||||||
|
|
||||||
|
Function type for middleware.
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Middleware func(Handler) Handler
|
||||||
|
```
|
||||||
|
|
||||||
|
### Group
|
||||||
|
|
||||||
|
Route group with a prefix.
|
||||||
|
|
||||||
|
```go
|
||||||
|
group := router.Group("/api")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Router Methods
|
||||||
|
|
||||||
|
### New()
|
||||||
|
|
||||||
|
Creates a new router.
|
||||||
|
|
||||||
|
```go
|
||||||
|
router := router.New()
|
||||||
|
```
|
||||||
|
|
||||||
|
### ServeHTTP(ctx)
|
||||||
|
|
||||||
|
Handler for fasthttp requests.
|
||||||
|
|
||||||
|
### Handler()
|
||||||
|
|
||||||
|
Returns a fasthttp.RequestHandler for use with fasthttp.ListenAndServe.
|
||||||
|
|
||||||
|
```go
|
||||||
|
fasthttp.ListenAndServe(":8080", router.Handler())
|
||||||
|
```
|
||||||
|
|
||||||
|
### Use(mw ...Middleware)
|
||||||
|
|
||||||
|
Adds global middleware.
|
||||||
|
|
||||||
|
```go
|
||||||
|
router.Use(loggingMiddleware, authMiddleware)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Handle(method, path, handler)
|
||||||
|
|
||||||
|
Registers a handler for the given method and path.
|
||||||
|
|
||||||
|
```go
|
||||||
|
router.Handle("GET", "/users", listUsersHandler)
|
||||||
|
```
|
||||||
|
|
||||||
|
### HTTP Method Shortcuts
|
||||||
|
|
||||||
|
```go
|
||||||
|
router.Get("/users", listUsersHandler)
|
||||||
|
router.Post("/users", createUserHandler)
|
||||||
|
router.Put("/users/[id]", updateUserHandler)
|
||||||
|
router.Patch("/users/[id]", patchUserHandler)
|
||||||
|
router.Delete("/users/[id]", deleteUserHandler)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Group(prefix)
|
||||||
|
|
||||||
|
Creates a route group with prefix.
|
||||||
|
|
||||||
|
```go
|
||||||
|
api := router.Group("/api")
|
||||||
|
```
|
||||||
|
|
||||||
|
### WithMiddleware(mw ...Middleware)
|
||||||
|
|
||||||
|
Applies middleware to the next route registration.
|
||||||
|
|
||||||
|
```go
|
||||||
|
router.WithMiddleware(authMiddleware).Get("/admin", adminHandler)
|
||||||
|
```
|
||||||
|
|
||||||
|
### StandardHandler(handler)
|
||||||
|
|
||||||
|
Adapts a standard fasthttp.RequestHandler to the router's Handler type.
|
||||||
|
|
||||||
|
```go
|
||||||
|
router.Get("/legacy", router.StandardHandler(legacyHandler))
|
||||||
|
```
|
||||||
|
|
||||||
|
## Group Methods
|
||||||
|
|
||||||
|
### Use(mw ...Middleware)
|
||||||
|
|
||||||
|
Adds middleware to the group.
|
||||||
|
|
||||||
|
```go
|
||||||
|
api.Use(apiKeyMiddleware)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Group(prefix)
|
||||||
|
|
||||||
|
Creates a nested group.
|
||||||
|
|
||||||
|
```go
|
||||||
|
v1 := api.Group("/v1")
|
||||||
|
```
|
||||||
|
|
||||||
|
### HTTP Method Shortcuts
|
||||||
|
|
||||||
|
```go
|
||||||
|
api.Get("/users", listUsersHandler)
|
||||||
|
api.Post("/users", createUserHandler)
|
||||||
|
api.Put("/users/[id]", updateUserHandler)
|
||||||
|
api.Patch("/users/[id]", patchUserHandler)
|
||||||
|
api.Delete("/users/[id]", deleteUserHandler)
|
||||||
|
```
|
||||||
|
|
||||||
|
### WithMiddleware(mw ...Middleware)
|
||||||
|
|
||||||
|
Applies middleware to the next route registration in this group.
|
||||||
|
|
||||||
|
```go
|
||||||
|
api.WithMiddleware(authMiddleware).Get("/admin", adminHandler)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Path Parameters
|
||||||
|
|
||||||
|
Dynamic segments in paths are defined using square brackets.
|
||||||
|
|
||||||
|
```go
|
||||||
|
router.Get("/users/[id]", func(ctx router.Ctx, params []string) {
|
||||||
|
id := params[0]
|
||||||
|
// ...
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Wildcards
|
||||||
|
|
||||||
|
Wildcard segments capture all remaining path segments.
|
||||||
|
|
||||||
|
```go
|
||||||
|
router.Get("/files/*path", func(ctx router.Ctx, params []string) {
|
||||||
|
path := params[0]
|
||||||
|
// ...
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- Wildcards must be the last segment in a path
|
||||||
|
- Only one wildcard is allowed per path
|
304
EXAMPLES.md
Normal file
304
EXAMPLES.md
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
# Examples
|
||||||
|
|
||||||
|
## Basic Usage
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/valyala/fasthttp"
|
||||||
|
"git.sharkk.net/Go/FastRouter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
r := router.New()
|
||||||
|
|
||||||
|
r.Get("/", func(ctx router.Ctx, _ []string) {
|
||||||
|
fmt.Fprintf(ctx, "Hello World!")
|
||||||
|
})
|
||||||
|
|
||||||
|
r.Get("/about", func(ctx router.Ctx, _ []string) {
|
||||||
|
fmt.Fprintf(ctx, "About page")
|
||||||
|
})
|
||||||
|
|
||||||
|
fasthttp.ListenAndServe(":8080", r.Handler())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Path Parameters
|
||||||
|
|
||||||
|
```go
|
||||||
|
r := router.New()
|
||||||
|
|
||||||
|
// Single parameter
|
||||||
|
r.Get("/users/[id]", func(ctx router.Ctx, params []string) {
|
||||||
|
id := params[0]
|
||||||
|
fmt.Fprintf(ctx, "User ID: %s", id)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Multiple parameters
|
||||||
|
r.Get("/posts/[category]/[id]", func(ctx router.Ctx, params []string) {
|
||||||
|
category := params[0]
|
||||||
|
id := params[1]
|
||||||
|
fmt.Fprintf(ctx, "Category: %s, Post ID: %s", category, id)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Wildcard
|
||||||
|
r.Get("/files/*path", func(ctx router.Ctx, params []string) {
|
||||||
|
path := params[0]
|
||||||
|
fmt.Fprintf(ctx, "File path: %s", path)
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Middleware
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Logging middleware
|
||||||
|
func LoggingMiddleware(next router.Handler) router.Handler {
|
||||||
|
return func(ctx router.Ctx, params []string) {
|
||||||
|
fmt.Printf("[%s] %s\n", string(ctx.Method()), string(ctx.Path()))
|
||||||
|
next(ctx, params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auth middleware
|
||||||
|
func AuthMiddleware(next router.Handler) router.Handler {
|
||||||
|
return func(ctx router.Ctx, params []string) {
|
||||||
|
token := string(ctx.Request.Header.Peek("Authorization"))
|
||||||
|
if token == "" {
|
||||||
|
ctx.Error("Unauthorized", fasthttp.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
next(ctx, params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global middleware
|
||||||
|
r := router.New()
|
||||||
|
r.Use(LoggingMiddleware)
|
||||||
|
|
||||||
|
// Route-specific middleware
|
||||||
|
r.WithMiddleware(AuthMiddleware).Get("/admin", adminHandler)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Route Groups
|
||||||
|
|
||||||
|
```go
|
||||||
|
r := router.New()
|
||||||
|
|
||||||
|
// API group
|
||||||
|
api := r.Group("/api")
|
||||||
|
api.Get("/status", statusHandler)
|
||||||
|
|
||||||
|
// Versioned API
|
||||||
|
v1 := api.Group("/v1")
|
||||||
|
v1.Get("/users", listUsersHandler)
|
||||||
|
v1.Post("/users", createUserHandler)
|
||||||
|
|
||||||
|
v2 := api.Group("/v2")
|
||||||
|
v2.Get("/users", listUsersV2Handler)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Using Standard fasthttp Handlers
|
||||||
|
|
||||||
|
```go
|
||||||
|
r := router.New()
|
||||||
|
|
||||||
|
// Using existing fasthttp handlers
|
||||||
|
r.Get("/legacy", router.StandardHandler(func(ctx *fasthttp.RequestCtx) {
|
||||||
|
fmt.Fprintf(ctx, "Legacy fasthttp handler")
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Mixing router handlers with standard handlers
|
||||||
|
r.Get("/users/[id]", func(ctx router.Ctx, params []string) {
|
||||||
|
// Get ID from params
|
||||||
|
id := params[0]
|
||||||
|
|
||||||
|
// Pass to standard handler
|
||||||
|
standardUserHandler := router.StandardHandler(func(ctx *fasthttp.RequestCtx) {
|
||||||
|
fmt.Fprintf(ctx, "Processing user: %s", id)
|
||||||
|
})
|
||||||
|
|
||||||
|
standardUserHandler(ctx, params)
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Combining Features
|
||||||
|
|
||||||
|
```go
|
||||||
|
r := router.New()
|
||||||
|
|
||||||
|
// Global middleware
|
||||||
|
r.Use(LoggingMiddleware)
|
||||||
|
|
||||||
|
// API group with middleware
|
||||||
|
api := r.Group("/api")
|
||||||
|
api.Use(ApiKeyMiddleware)
|
||||||
|
|
||||||
|
// Admin group with auth middleware
|
||||||
|
admin := r.Group("/admin")
|
||||||
|
admin.Use(AuthMiddleware)
|
||||||
|
|
||||||
|
// Users endpoints with versioning
|
||||||
|
users := api.Group("/v1/users")
|
||||||
|
users.Get("/", listUsersHandler)
|
||||||
|
users.Post("/", createUserHandler)
|
||||||
|
users.Get("/[id]", getUserHandler)
|
||||||
|
users.Put("/[id]", updateUserHandler)
|
||||||
|
users.Delete("/[id]", deleteUserHandler)
|
||||||
|
|
||||||
|
// Special case with route-specific middleware
|
||||||
|
api.WithMiddleware(CacheMiddleware).Get("/cached-resource", cachedResourceHandler)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
```go
|
||||||
|
r := router.New()
|
||||||
|
|
||||||
|
err := r.Get("/users/[id]", getUserHandler)
|
||||||
|
if err != nil {
|
||||||
|
// Handle error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom NotFound handler
|
||||||
|
r.ServeHTTP = func(ctx *fasthttp.RequestCtx) {
|
||||||
|
path := string(ctx.Path())
|
||||||
|
method := string(ctx.Method())
|
||||||
|
|
||||||
|
h, params, found := r.Lookup(method, path)
|
||||||
|
if !found {
|
||||||
|
// Custom 404 handler
|
||||||
|
ctx.SetStatusCode(fasthttp.StatusNotFound)
|
||||||
|
fmt.Fprintf(ctx, "Custom 404: %s not found", path)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h(ctx, params)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Complete Application Example
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/valyala/fasthttp"
|
||||||
|
"github.com/yourusername/fastrouter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
r := router.New()
|
||||||
|
|
||||||
|
// Global middleware
|
||||||
|
r.Use(LoggingMiddleware)
|
||||||
|
|
||||||
|
// Basic routes
|
||||||
|
r.Get("/", homeHandler)
|
||||||
|
r.Get("/about", aboutHandler)
|
||||||
|
|
||||||
|
// API routes
|
||||||
|
api := r.Group("/api")
|
||||||
|
api.Use(ApiKeyMiddleware)
|
||||||
|
|
||||||
|
// Users API
|
||||||
|
users := api.Group("/users")
|
||||||
|
users.Get("/", listUsersHandler)
|
||||||
|
users.Post("/", createUserHandler)
|
||||||
|
users.Get("/[id]", getUserHandler)
|
||||||
|
users.Put("/[id]", updateUserHandler)
|
||||||
|
users.Delete("/[id]", deleteUserHandler)
|
||||||
|
|
||||||
|
// Admin routes with auth
|
||||||
|
admin := r.Group("/admin")
|
||||||
|
admin.Use(AuthMiddleware)
|
||||||
|
admin.Get("/", adminDashboardHandler)
|
||||||
|
admin.Get("/users", adminUsersHandler)
|
||||||
|
|
||||||
|
// Start server
|
||||||
|
log.Println("Server starting on :8080")
|
||||||
|
log.Fatal(fasthttp.ListenAndServe(":8080", r.Handler()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handlers
|
||||||
|
func homeHandler(ctx router.Ctx, _ []string) {
|
||||||
|
fmt.Fprintf(ctx, "Welcome to the home page")
|
||||||
|
}
|
||||||
|
|
||||||
|
func aboutHandler(ctx router.Ctx, _ []string) {
|
||||||
|
fmt.Fprintf(ctx, "About us")
|
||||||
|
}
|
||||||
|
|
||||||
|
func listUsersHandler(ctx router.Ctx, _ []string) {
|
||||||
|
fmt.Fprintf(ctx, "List of users")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUserHandler(ctx router.Ctx, params []string) {
|
||||||
|
id := params[0]
|
||||||
|
fmt.Fprintf(ctx, "User details for ID: %s", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createUserHandler(ctx router.Ctx, _ []string) {
|
||||||
|
// Parse form data or JSON body
|
||||||
|
// You can use ctx.PostBody() to get the request body
|
||||||
|
fmt.Fprintf(ctx, "User created")
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateUserHandler(ctx router.Ctx, params []string) {
|
||||||
|
id := params[0]
|
||||||
|
fmt.Fprintf(ctx, "User updated: %s", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteUserHandler(ctx router.Ctx, params []string) {
|
||||||
|
id := params[0]
|
||||||
|
fmt.Fprintf(ctx, "User deleted: %s", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func adminDashboardHandler(ctx router.Ctx, _ []string) {
|
||||||
|
fmt.Fprintf(ctx, "Admin Dashboard")
|
||||||
|
}
|
||||||
|
|
||||||
|
func adminUsersHandler(ctx router.Ctx, _ []string) {
|
||||||
|
fmt.Fprintf(ctx, "Admin Users Management")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Middleware
|
||||||
|
func LoggingMiddleware(next router.Handler) router.Handler {
|
||||||
|
return func(ctx router.Ctx, params []string) {
|
||||||
|
log.Printf("[%s] %s", string(ctx.Method()), string(ctx.Path()))
|
||||||
|
next(ctx, params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ApiKeyMiddleware(next router.Handler) router.Handler {
|
||||||
|
return func(ctx router.Ctx, params []string) {
|
||||||
|
apiKey := string(ctx.Request.Header.Peek("X-API-Key"))
|
||||||
|
if apiKey == "" {
|
||||||
|
ctx.Error("API key required", fasthttp.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
next(ctx, params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AuthMiddleware(next router.Handler) router.Handler {
|
||||||
|
return func(ctx router.Ctx, params []string) {
|
||||||
|
// Check session or JWT
|
||||||
|
authorized := checkUserAuth(ctx)
|
||||||
|
if !authorized {
|
||||||
|
ctx.Redirect("/login", fasthttp.StatusSeeOther)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
next(ctx, params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkUserAuth(ctx router.Ctx) bool {
|
||||||
|
// Implementation of auth check
|
||||||
|
return len(ctx.Request.Header.Peek("Authorization")) > 0
|
||||||
|
}
|
||||||
|
```
|
426
router.go
426
router.go
@ -6,39 +6,36 @@ import (
|
|||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Ctx is an alias for fasthttp.RequestCtx for shorter, cleaner code
|
|
||||||
type Ctx = *fasthttp.RequestCtx
|
type Ctx = *fasthttp.RequestCtx
|
||||||
|
|
||||||
// Handler is an interface for handling HTTP requests with path parameters.
|
// Handler is a request handler with parameters.
|
||||||
type Handler interface {
|
type Handler func(ctx Ctx, params []string)
|
||||||
Serve(ctx Ctx, params []string)
|
|
||||||
|
func (h Handler) Serve(ctx Ctx, params []string) {
|
||||||
|
h(ctx, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Middleware wraps a handler with additional functionality.
|
|
||||||
type Middleware func(Handler) Handler
|
type Middleware func(Handler) Handler
|
||||||
|
|
||||||
// node represents a segment in the URL path and its handling logic.
|
|
||||||
type node struct {
|
type node struct {
|
||||||
segment string // the path segment this node matches
|
segment string
|
||||||
handler Handler // handler for this path, if it's an endpoint
|
handler Handler
|
||||||
children []*node // child nodes for subsequent path segments
|
children []*node
|
||||||
isDynamic bool // true for param segments like [id]
|
isDynamic bool
|
||||||
isWildcard bool // true for catch-all segments like *filepath
|
isWildcard bool
|
||||||
maxParams uint8 // maximum number of parameters in paths under this node
|
maxParams uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
// Router routes HTTP requests by method and path.
|
|
||||||
// It supports static paths, path parameters, wildcards, and middleware.
|
|
||||||
type Router struct {
|
type Router struct {
|
||||||
get *node
|
get *node
|
||||||
post *node
|
post *node
|
||||||
put *node
|
put *node
|
||||||
patch *node
|
patch *node
|
||||||
delete *node
|
delete *node
|
||||||
middleware []Middleware // Global middleware
|
middleware []Middleware
|
||||||
|
paramsBuffer []string // Pre-allocated buffer for parameters
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group represents a route group with a path prefix and shared middleware.
|
|
||||||
type Group struct {
|
type Group struct {
|
||||||
router *Router
|
router *Router
|
||||||
prefix string
|
prefix string
|
||||||
@ -48,12 +45,13 @@ type Group struct {
|
|||||||
// New creates a new Router instance.
|
// New creates a new Router instance.
|
||||||
func New() *Router {
|
func New() *Router {
|
||||||
return &Router{
|
return &Router{
|
||||||
get: &node{},
|
get: &node{},
|
||||||
post: &node{},
|
post: &node{},
|
||||||
put: &node{},
|
put: &node{},
|
||||||
patch: &node{},
|
patch: &node{},
|
||||||
delete: &node{},
|
delete: &node{},
|
||||||
middleware: []Middleware{},
|
middleware: []Middleware{},
|
||||||
|
paramsBuffer: make([]string, 64),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,13 +60,13 @@ func (r *Router) ServeHTTP(ctx *fasthttp.RequestCtx) {
|
|||||||
path := string(ctx.Path())
|
path := string(ctx.Path())
|
||||||
method := string(ctx.Method())
|
method := string(ctx.Method())
|
||||||
|
|
||||||
handler, params, found := r.Lookup(method, path)
|
h, params, found := r.Lookup(method, path)
|
||||||
if !found {
|
if !found {
|
||||||
ctx.SetStatusCode(fasthttp.StatusNotFound)
|
ctx.SetStatusCode(fasthttp.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
handler.Serve(ctx, params)
|
h(ctx, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handler returns a fasthttp request handler
|
// Handler returns a fasthttp request handler
|
||||||
@ -76,38 +74,24 @@ func (r *Router) Handler() fasthttp.RequestHandler {
|
|||||||
return r.ServeHTTP
|
return r.ServeHTTP
|
||||||
}
|
}
|
||||||
|
|
||||||
// simpleHandler implements the Handler interface
|
// Use adds middleware to the router.
|
||||||
type simpleHandler struct {
|
func (r *Router) Use(mw ...Middleware) *Router {
|
||||||
fn func(ctx Ctx, params []string)
|
r.middleware = append(r.middleware, mw...)
|
||||||
}
|
|
||||||
|
|
||||||
// Serve executes the handler function with params
|
|
||||||
func (h *simpleHandler) Serve(ctx Ctx, params []string) {
|
|
||||||
h.fn(ctx, params)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use adds middleware to the router's global middleware stack.
|
|
||||||
func (r *Router) Use(middleware ...Middleware) *Router {
|
|
||||||
r.middleware = append(r.middleware, middleware...)
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group creates a new route group with the given path prefix.
|
// Group creates a new route group.
|
||||||
func (r *Router) Group(prefix string) *Group {
|
func (r *Router) Group(prefix string) *Group {
|
||||||
return &Group{
|
return &Group{router: r, prefix: prefix, middleware: []Middleware{}}
|
||||||
router: r,
|
|
||||||
prefix: prefix,
|
|
||||||
middleware: []Middleware{},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use adds middleware to the group's middleware stack.
|
// Use adds middleware to the group.
|
||||||
func (g *Group) Use(middleware ...Middleware) *Group {
|
func (g *Group) Use(mw ...Middleware) *Group {
|
||||||
g.middleware = append(g.middleware, middleware...)
|
g.middleware = append(g.middleware, mw...)
|
||||||
return g
|
return g
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group creates a nested group with an additional prefix.
|
// Group creates a nested group.
|
||||||
func (g *Group) Group(prefix string) *Group {
|
func (g *Group) Group(prefix string) *Group {
|
||||||
return &Group{
|
return &Group{
|
||||||
router: g.router,
|
router: g.router,
|
||||||
@ -116,28 +100,23 @@ func (g *Group) Group(prefix string) *Group {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// applyMiddleware wraps a handler with middleware in reverse order.
|
// applyMiddleware applies middleware in reverse order.
|
||||||
func applyMiddleware(handler Handler, middleware []Middleware) Handler {
|
func applyMiddleware(h Handler, mw []Middleware) Handler {
|
||||||
h := handler
|
for i := len(mw) - 1; i >= 0; i-- {
|
||||||
for i := len(middleware) - 1; i >= 0; i-- {
|
h = mw[i](h)
|
||||||
h = middleware[i](h)
|
|
||||||
}
|
}
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandlerFunc is a function that handles HTTP requests with parameters.
|
|
||||||
type HandlerFunc func(ctx Ctx, params []string)
|
|
||||||
|
|
||||||
// Handle registers a handler for the given method and path.
|
// Handle registers a handler for the given method and path.
|
||||||
func (r *Router) Handle(method, path string, handler HandlerFunc) error {
|
func (r *Router) Handle(method, path string, h Handler) error {
|
||||||
root := r.methodNode(method)
|
root := r.methodNode(method)
|
||||||
if root == nil {
|
if root == nil {
|
||||||
return fmt.Errorf("unsupported method: %s", method)
|
return fmt.Errorf("unsupported method: %s", method)
|
||||||
}
|
}
|
||||||
return r.addRoute(root, path, &simpleHandler{fn: handler}, r.middleware)
|
return r.addRoute(root, path, h, r.middleware)
|
||||||
}
|
}
|
||||||
|
|
||||||
// methodNode returns the root node for the given HTTP method.
|
|
||||||
func (r *Router) methodNode(method string) *node {
|
func (r *Router) methodNode(method string) *node {
|
||||||
switch method {
|
switch method {
|
||||||
case "GET":
|
case "GET":
|
||||||
@ -155,335 +134,302 @@ func (r *Router) methodNode(method string) *node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get registers a handler for GET requests at the given path.
|
// Get registers a GET handler.
|
||||||
func (r *Router) Get(path string, handler HandlerFunc) error {
|
func (r *Router) Get(path string, h Handler) error {
|
||||||
return r.Handle("GET", path, handler)
|
return r.Handle("GET", path, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Post registers a handler for POST requests at the given path.
|
// Post registers a POST handler.
|
||||||
func (r *Router) Post(path string, handler HandlerFunc) error {
|
func (r *Router) Post(path string, h Handler) error {
|
||||||
return r.Handle("POST", path, handler)
|
return r.Handle("POST", path, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put registers a handler for PUT requests at the given path.
|
// Put registers a PUT handler.
|
||||||
func (r *Router) Put(path string, handler HandlerFunc) error {
|
func (r *Router) Put(path string, h Handler) error {
|
||||||
return r.Handle("PUT", path, handler)
|
return r.Handle("PUT", path, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Patch registers a handler for PATCH requests at the given path.
|
// Patch registers a PATCH handler.
|
||||||
func (r *Router) Patch(path string, handler HandlerFunc) error {
|
func (r *Router) Patch(path string, h Handler) error {
|
||||||
return r.Handle("PATCH", path, handler)
|
return r.Handle("PATCH", path, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete registers a handler for DELETE requests at the given path.
|
// Delete registers a DELETE handler.
|
||||||
func (r *Router) Delete(path string, handler HandlerFunc) error {
|
func (r *Router) Delete(path string, h Handler) error {
|
||||||
return r.Handle("DELETE", path, handler)
|
return r.Handle("DELETE", path, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildGroupMiddleware returns combined middleware for the group
|
|
||||||
func (g *Group) buildGroupMiddleware() []Middleware {
|
func (g *Group) buildGroupMiddleware() []Middleware {
|
||||||
middleware := append([]Middleware{}, g.router.middleware...)
|
mw := append([]Middleware{}, g.router.middleware...)
|
||||||
return append(middleware, g.middleware...)
|
return append(mw, g.middleware...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle registers a handler for the given method and path.
|
// Handle registers a handler in the group.
|
||||||
func (g *Group) Handle(method, path string, handler HandlerFunc) error {
|
func (g *Group) Handle(method, path string, h Handler) error {
|
||||||
root := g.router.methodNode(method)
|
root := g.router.methodNode(method)
|
||||||
if root == nil {
|
if root == nil {
|
||||||
return fmt.Errorf("unsupported method: %s", method)
|
return fmt.Errorf("unsupported method: %s", method)
|
||||||
}
|
}
|
||||||
|
return g.router.addRoute(root, g.prefix+path, h, g.buildGroupMiddleware())
|
||||||
fullPath := g.prefix + path
|
|
||||||
return g.router.addRoute(root, fullPath, &simpleHandler{fn: handler}, g.buildGroupMiddleware())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get registers a handler for GET requests at the given path.
|
// Get registers a GET handler in the group.
|
||||||
func (g *Group) Get(path string, handler HandlerFunc) error {
|
func (g *Group) Get(path string, h Handler) error {
|
||||||
return g.Handle("GET", path, handler)
|
return g.Handle("GET", path, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Post registers a handler for POST requests at the given path.
|
// Post registers a POST handler in the group.
|
||||||
func (g *Group) Post(path string, handler HandlerFunc) error {
|
func (g *Group) Post(path string, h Handler) error {
|
||||||
return g.Handle("POST", path, handler)
|
return g.Handle("POST", path, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put registers a handler for PUT requests at the given path.
|
// Put registers a PUT handler in the group.
|
||||||
func (g *Group) Put(path string, handler HandlerFunc) error {
|
func (g *Group) Put(path string, h Handler) error {
|
||||||
return g.Handle("PUT", path, handler)
|
return g.Handle("PUT", path, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Patch registers a handler for PATCH requests at the given path.
|
// Patch registers a PATCH handler in the group.
|
||||||
func (g *Group) Patch(path string, handler HandlerFunc) error {
|
func (g *Group) Patch(path string, h Handler) error {
|
||||||
return g.Handle("PATCH", path, handler)
|
return g.Handle("PATCH", path, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete registers a handler for DELETE requests at the given path.
|
// Delete registers a DELETE handler in the group.
|
||||||
func (g *Group) Delete(path string, handler HandlerFunc) error {
|
func (g *Group) Delete(path string, h Handler) error {
|
||||||
return g.Handle("DELETE", path, handler)
|
return g.Handle("DELETE", path, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithMiddleware applies specific middleware to the next route registration.
|
// WithMiddleware applies specific middleware for next registration.
|
||||||
func (r *Router) WithMiddleware(middleware ...Middleware) *MiddlewareRouter {
|
func (r *Router) WithMiddleware(mw ...Middleware) *MiddlewareRouter {
|
||||||
return &MiddlewareRouter{
|
return &MiddlewareRouter{router: r, middleware: mw}
|
||||||
router: r,
|
|
||||||
middleware: middleware,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithMiddleware applies specific middleware to the next route registration.
|
// WithMiddleware applies specific middleware for next group route.
|
||||||
func (g *Group) WithMiddleware(middleware ...Middleware) *MiddlewareGroup {
|
func (g *Group) WithMiddleware(mw ...Middleware) *MiddlewareGroup {
|
||||||
return &MiddlewareGroup{
|
return &MiddlewareGroup{group: g, middleware: mw}
|
||||||
group: g,
|
|
||||||
middleware: middleware,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MiddlewareRouter handles route registration with specific middleware.
|
|
||||||
type MiddlewareRouter struct {
|
type MiddlewareRouter struct {
|
||||||
router *Router
|
router *Router
|
||||||
middleware []Middleware
|
middleware []Middleware
|
||||||
}
|
}
|
||||||
|
|
||||||
// MiddlewareGroup handles group route registration with specific middleware.
|
|
||||||
type MiddlewareGroup struct {
|
type MiddlewareGroup struct {
|
||||||
group *Group
|
group *Group
|
||||||
middleware []Middleware
|
middleware []Middleware
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildMiddleware returns combined middleware for the middleware router
|
|
||||||
func (mr *MiddlewareRouter) buildMiddleware() []Middleware {
|
func (mr *MiddlewareRouter) buildMiddleware() []Middleware {
|
||||||
middleware := append([]Middleware{}, mr.router.middleware...)
|
mw := append([]Middleware{}, mr.router.middleware...)
|
||||||
return append(middleware, mr.middleware...)
|
return append(mw, mr.middleware...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle registers a handler for the given method and path.
|
// Handle registers a handler with middleware router.
|
||||||
func (mr *MiddlewareRouter) Handle(method, path string, handler HandlerFunc) error {
|
func (mr *MiddlewareRouter) Handle(method, path string, h Handler) error {
|
||||||
root := mr.router.methodNode(method)
|
root := mr.router.methodNode(method)
|
||||||
if root == nil {
|
if root == nil {
|
||||||
return fmt.Errorf("unsupported method: %s", method)
|
return fmt.Errorf("unsupported method: %s", method)
|
||||||
}
|
}
|
||||||
|
return mr.router.addRoute(root, path, h, mr.buildMiddleware())
|
||||||
return mr.router.addRoute(root, path, &simpleHandler{fn: handler}, mr.buildMiddleware())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get registers a handler for GET requests with specific middleware.
|
// Get registers a GET handler with middleware router.
|
||||||
func (mr *MiddlewareRouter) Get(path string, handler HandlerFunc) error {
|
func (mr *MiddlewareRouter) Get(path string, h Handler) error {
|
||||||
return mr.Handle("GET", path, handler)
|
return mr.Handle("GET", path, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Post registers a handler for POST requests with specific middleware.
|
// Post registers a POST handler with middleware router.
|
||||||
func (mr *MiddlewareRouter) Post(path string, handler HandlerFunc) error {
|
func (mr *MiddlewareRouter) Post(path string, h Handler) error {
|
||||||
return mr.Handle("POST", path, handler)
|
return mr.Handle("POST", path, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put registers a handler for PUT requests with specific middleware.
|
// Put registers a PUT handler with middleware router.
|
||||||
func (mr *MiddlewareRouter) Put(path string, handler HandlerFunc) error {
|
func (mr *MiddlewareRouter) Put(path string, h Handler) error {
|
||||||
return mr.Handle("PUT", path, handler)
|
return mr.Handle("PUT", path, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Patch registers a handler for PATCH requests with specific middleware.
|
// Patch registers a PATCH handler with middleware router.
|
||||||
func (mr *MiddlewareRouter) Patch(path string, handler HandlerFunc) error {
|
func (mr *MiddlewareRouter) Patch(path string, h Handler) error {
|
||||||
return mr.Handle("PATCH", path, handler)
|
return mr.Handle("PATCH", path, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete registers a handler for DELETE requests with specific middleware.
|
// Delete registers a DELETE handler with middleware router.
|
||||||
func (mr *MiddlewareRouter) Delete(path string, handler HandlerFunc) error {
|
func (mr *MiddlewareRouter) Delete(path string, h Handler) error {
|
||||||
return mr.Handle("DELETE", path, handler)
|
return mr.Handle("DELETE", path, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildMiddleware returns combined middleware for the middleware group
|
|
||||||
func (mg *MiddlewareGroup) buildMiddleware() []Middleware {
|
func (mg *MiddlewareGroup) buildMiddleware() []Middleware {
|
||||||
middleware := append([]Middleware{}, mg.group.router.middleware...)
|
mw := append([]Middleware{}, mg.group.router.middleware...)
|
||||||
middleware = append(middleware, mg.group.middleware...)
|
mw = append(mw, mg.group.middleware...)
|
||||||
return append(middleware, mg.middleware...)
|
return append(mw, mg.middleware...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle registers a handler for the given method and path.
|
// Handle registers a handler with middleware group.
|
||||||
func (mg *MiddlewareGroup) Handle(method, path string, handler HandlerFunc) error {
|
func (mg *MiddlewareGroup) Handle(method, path string, h Handler) error {
|
||||||
root := mg.group.router.methodNode(method)
|
root := mg.group.router.methodNode(method)
|
||||||
if root == nil {
|
if root == nil {
|
||||||
return fmt.Errorf("unsupported method: %s", method)
|
return fmt.Errorf("unsupported method: %s", method)
|
||||||
}
|
}
|
||||||
|
return mg.group.router.addRoute(root, mg.group.prefix+path, h, mg.buildMiddleware())
|
||||||
fullPath := mg.group.prefix + path
|
|
||||||
return mg.group.router.addRoute(root, fullPath, &simpleHandler{fn: handler}, mg.buildMiddleware())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get registers a handler for GET requests with specific middleware.
|
// Get registers a GET handler with middleware group.
|
||||||
func (mg *MiddlewareGroup) Get(path string, handler HandlerFunc) error {
|
func (mg *MiddlewareGroup) Get(path string, h Handler) error {
|
||||||
return mg.Handle("GET", path, handler)
|
return mg.Handle("GET", path, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Post registers a handler for POST requests with specific middleware.
|
// Post registers a POST handler with middleware group.
|
||||||
func (mg *MiddlewareGroup) Post(path string, handler HandlerFunc) error {
|
func (mg *MiddlewareGroup) Post(path string, h Handler) error {
|
||||||
return mg.Handle("POST", path, handler)
|
return mg.Handle("POST", path, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put registers a handler for PUT requests with specific middleware.
|
// Put registers a PUT handler with middleware group.
|
||||||
func (mg *MiddlewareGroup) Put(path string, handler HandlerFunc) error {
|
func (mg *MiddlewareGroup) Put(path string, h Handler) error {
|
||||||
return mg.Handle("PUT", path, handler)
|
return mg.Handle("PUT", path, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Patch registers a handler for PATCH requests with specific middleware.
|
// Patch registers a PATCH handler with middleware group.
|
||||||
func (mg *MiddlewareGroup) Patch(path string, handler HandlerFunc) error {
|
func (mg *MiddlewareGroup) Patch(path string, h Handler) error {
|
||||||
return mg.Handle("PATCH", path, handler)
|
return mg.Handle("PATCH", path, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete registers a handler for DELETE requests with specific middleware.
|
// Delete registers a DELETE handler with middleware group.
|
||||||
func (mg *MiddlewareGroup) Delete(path string, handler HandlerFunc) error {
|
func (mg *MiddlewareGroup) Delete(path string, h Handler) error {
|
||||||
return mg.Handle("DELETE", path, handler)
|
return mg.Handle("DELETE", path, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// StandardHandler adapts a standard fasthttp.RequestHandler to the router's HandlerFunc
|
// StandardHandler adapts a standard fasthttp.RequestHandler to the router's Handler
|
||||||
func StandardHandler(handler fasthttp.RequestHandler) HandlerFunc {
|
func StandardHandler(handler fasthttp.RequestHandler) Handler {
|
||||||
return func(ctx Ctx, _ []string) {
|
return func(ctx Ctx, _ []string) {
|
||||||
handler(ctx)
|
handler(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// readSegment extracts the next path segment starting at the given position.
|
// readSegment extracts the next path segment.
|
||||||
// Returns the segment, the position after it, and whether there are more segments.
|
|
||||||
func readSegment(path string, start int) (segment string, end int, hasMore bool) {
|
func readSegment(path string, start int) (segment string, end int, hasMore bool) {
|
||||||
if start >= len(path) {
|
if start >= len(path) {
|
||||||
return "", start, false
|
return "", start, false
|
||||||
}
|
}
|
||||||
|
|
||||||
if path[start] == '/' {
|
if path[start] == '/' {
|
||||||
start++
|
start++
|
||||||
}
|
}
|
||||||
|
|
||||||
if start >= len(path) {
|
if start >= len(path) {
|
||||||
return "", start, false
|
return "", start, false
|
||||||
}
|
}
|
||||||
|
|
||||||
end = start
|
end = start
|
||||||
for end < len(path) && path[end] != '/' {
|
for end < len(path) && path[end] != '/' {
|
||||||
end++
|
end++
|
||||||
}
|
}
|
||||||
|
|
||||||
return path[start:end], end, end < len(path)
|
return path[start:end], end, end < len(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// addRoute adds a new route to the prefix tree with middleware.
|
// addRoute adds a new route to the trie.
|
||||||
func (r *Router) addRoute(root *node, path string, handler Handler, middleware []Middleware) error {
|
func (r *Router) addRoute(root *node, path string, h Handler, mw []Middleware) error {
|
||||||
wrappedHandler := applyMiddleware(handler, middleware)
|
h = applyMiddleware(h, mw)
|
||||||
|
|
||||||
if path == "/" {
|
if path == "/" {
|
||||||
root.handler = wrappedHandler
|
root.handler = h
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
current := root
|
current := root
|
||||||
pos := 0
|
pos := 0
|
||||||
var lastWildcard bool
|
lastWC := false
|
||||||
paramsCount := uint8(0)
|
count := uint8(0)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
segment, newPos, hasMore := readSegment(path, pos)
|
seg, newPos, more := readSegment(path, pos)
|
||||||
if segment == "" {
|
if seg == "" {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
isDyn := len(seg) > 2 && seg[0] == '[' && seg[len(seg)-1] == ']'
|
||||||
isDynamic := len(segment) > 2 && segment[0] == '[' && segment[len(segment)-1] == ']'
|
isWC := len(seg) > 0 && seg[0] == '*'
|
||||||
isWildcard := len(segment) > 0 && segment[0] == '*'
|
if isWC {
|
||||||
|
if lastWC || more {
|
||||||
if isWildcard {
|
|
||||||
if lastWildcard {
|
|
||||||
return fmt.Errorf("wildcard must be the last segment in the path")
|
return fmt.Errorf("wildcard must be the last segment in the path")
|
||||||
}
|
}
|
||||||
if hasMore {
|
lastWC = true
|
||||||
return fmt.Errorf("wildcard must be the last segment in the path")
|
|
||||||
}
|
|
||||||
lastWildcard = true
|
|
||||||
}
|
}
|
||||||
|
if isDyn || isWC {
|
||||||
if isDynamic || isWildcard {
|
count++
|
||||||
paramsCount++
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var child *node
|
var child *node
|
||||||
for _, n := range current.children {
|
for _, c := range current.children {
|
||||||
if n.segment == segment {
|
if c.segment == seg {
|
||||||
child = n
|
child = c
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if child == nil {
|
if child == nil {
|
||||||
child = &node{
|
child = &node{segment: seg, isDynamic: isDyn, isWildcard: isWC}
|
||||||
segment: segment,
|
|
||||||
isDynamic: isDynamic,
|
|
||||||
isWildcard: isWildcard,
|
|
||||||
}
|
|
||||||
current.children = append(current.children, child)
|
current.children = append(current.children, child)
|
||||||
}
|
}
|
||||||
|
if child.maxParams < count {
|
||||||
if child.maxParams < paramsCount {
|
child.maxParams = count
|
||||||
child.maxParams = paramsCount
|
|
||||||
}
|
}
|
||||||
current = child
|
current = child
|
||||||
pos = newPos
|
pos = newPos
|
||||||
}
|
}
|
||||||
|
current.handler = h
|
||||||
current.handler = wrappedHandler
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lookup finds a handler matching the given method and path.
|
// Lookup finds a handler matching method and path.
|
||||||
// Returns the handler, any captured parameters, and whether a match was found.
|
|
||||||
func (r *Router) Lookup(method, path string) (Handler, []string, bool) {
|
func (r *Router) Lookup(method, path string) (Handler, []string, bool) {
|
||||||
root := r.methodNode(method)
|
root := r.methodNode(method)
|
||||||
if root == nil {
|
if root == nil {
|
||||||
return nil, nil, false
|
return nil, nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
if path == "/" {
|
if path == "/" {
|
||||||
return root.handler, []string{}, root.handler != nil
|
return root.handler, nil, root.handler != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
params := make([]string, 0, root.maxParams)
|
buffer := r.paramsBuffer
|
||||||
h, found := match(root, path, 0, ¶ms)
|
if cap(buffer) < int(root.maxParams) {
|
||||||
|
buffer = make([]string, root.maxParams)
|
||||||
|
r.paramsBuffer = buffer
|
||||||
|
}
|
||||||
|
buffer = buffer[:0]
|
||||||
|
|
||||||
|
h, paramCount, found := match(root, path, 0, &buffer)
|
||||||
if !found {
|
if !found {
|
||||||
return nil, nil, false
|
return nil, nil, false
|
||||||
}
|
}
|
||||||
return h, params, true
|
|
||||||
|
return h, buffer[:paramCount], true
|
||||||
}
|
}
|
||||||
|
|
||||||
// match recursively traverses the prefix tree to find a matching handler.
|
// match traverses the trie to find a handler.
|
||||||
// It populates params with any captured path parameters or wildcard matches.
|
func match(current *node, path string, start int, params *[]string) (Handler, int, bool) {
|
||||||
func match(current *node, path string, start int, params *[]string) (Handler, bool) {
|
paramCount := 0
|
||||||
// Check for wildcard children first
|
|
||||||
for _, child := range current.children {
|
for _, c := range current.children {
|
||||||
if child.isWildcard {
|
if c.isWildcard {
|
||||||
remaining := path[start:]
|
rem := path[start:]
|
||||||
if len(remaining) > 0 && remaining[0] == '/' {
|
if len(rem) > 0 && rem[0] == '/' {
|
||||||
remaining = remaining[1:]
|
rem = rem[1:]
|
||||||
}
|
}
|
||||||
*params = append(*params, remaining)
|
*params = append(*params, rem)
|
||||||
return child.handler, child.handler != nil
|
return c.handler, 1, c.handler != nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read current segment
|
seg, pos, more := readSegment(path, start)
|
||||||
segment, pos, hasMore := readSegment(path, start)
|
if seg == "" {
|
||||||
if segment == "" {
|
return current.handler, 0, current.handler != nil
|
||||||
return current.handler, current.handler != nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to match children
|
for _, c := range current.children {
|
||||||
for _, child := range current.children {
|
if c.segment == seg || c.isDynamic {
|
||||||
if child.segment == segment || child.isDynamic {
|
if c.isDynamic {
|
||||||
if child.isDynamic {
|
*params = append(*params, seg)
|
||||||
*params = append(*params, segment)
|
paramCount++
|
||||||
}
|
}
|
||||||
if !hasMore {
|
if !more {
|
||||||
return child.handler, child.handler != nil
|
return c.handler, paramCount, c.handler != nil
|
||||||
}
|
}
|
||||||
if h, found := match(child, path, pos, params); found {
|
h, nestedCount, ok := match(c, path, pos, params)
|
||||||
return h, true
|
if ok {
|
||||||
|
return h, paramCount + nestedCount, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, false
|
return nil, 0, false
|
||||||
}
|
}
|
||||||
|
@ -9,18 +9,9 @@ import (
|
|||||||
"github.com/valyala/fasthttp/fasthttputil"
|
"github.com/valyala/fasthttp/fasthttputil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// simpleHandler implements the Handler interface
|
|
||||||
type testHandler struct {
|
|
||||||
fn func(ctx Ctx, params []string)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *testHandler) Serve(ctx Ctx, params []string) {
|
|
||||||
h.fn(ctx, params)
|
|
||||||
}
|
|
||||||
|
|
||||||
// newHandler creates a simple Handler from a function
|
// newHandler creates a simple Handler from a function
|
||||||
func newHandler(fn func(ctx Ctx, params []string)) Handler {
|
func newHandler(fn func(ctx Ctx, params []string)) Handler {
|
||||||
return &testHandler{fn: fn}
|
return fn
|
||||||
}
|
}
|
||||||
|
|
||||||
// performRequest is a helper function to test the router
|
// performRequest is a helper function to test the router
|
||||||
|
Loading…
x
Reference in New Issue
Block a user