-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrouter.go
More file actions
executable file
·158 lines (131 loc) · 3.98 KB
/
Copy pathrouter.go
File metadata and controls
executable file
·158 lines (131 loc) · 3.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// Copyright (c) 2024, Roel Schut. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package serv
import (
"net/http"
"sync"
)
// RouteHandler handles routes.
type RouteHandler interface {
HandleRoute(route Route)
}
// RoutesRegisterer registers routes to a [RouteHandler].
type RoutesRegisterer interface {
RegisterRoutes(rh RouteHandler)
}
// RoutesRegistererFunc registers routes to a [RouteHandler].
type RoutesRegistererFunc func(rh RouteHandler)
func (fn RoutesRegistererFunc) RegisterRoutes(rh RouteHandler) { fn(rh) }
// RegisterRoutes registers [Route]s to a [RouteHandler].
func RegisterRoutes(rh RouteHandler, routes ...Route) {
for _, r := range routes {
rh.HandleRoute(r)
}
}
var _ http.Handler = (*Route)(nil)
// Route is a [http.Handler] which represents a route that can be registered to
// a [RouteHandler].
type Route struct {
// Name of the route.
Name string
// Method used to handle the route.
Method string
// Pattern to access the route.
Pattern string
// Handler is the [http.Handler] that handles the route.
Handler http.Handler
}
// GetHandler returns the [Route]'s Handler and wraps it with [AddHandlerName]
// when Name is set.
func (r Route) GetHandler() http.Handler {
if r.Name == "" {
return r.Handler
}
return AddHandlerName(r.Name, r.Handler)
}
func (r Route) ServeHTTP(wri http.ResponseWriter, req *http.Request) {
r.GetHandler().ServeHTTP(wri, req)
}
// Router is a [http.Handler] that can handle routes.
type Router interface {
RouteHandler
http.Handler
}
var (
_ Router = (*ServeMux)(nil)
_ Option = (*ServeMux)(nil)
)
type serveMux = http.ServeMux
// ServeMux uses an internal embedded [http.ServeMux] to handle routes. It
// implements the [Router] interface on top of that.
// See [http.ServeMux] for additional information about pattern syntax,
// compatibility etc.
type ServeMux struct {
*serveMux
mut sync.RWMutex
notFound http.Handler
}
// NewServeMux creates a new [ServeMux] and is ready to be used.
func NewServeMux() *ServeMux {
return &ServeMux{serveMux: http.NewServeMux()}
}
var defaultServeMux = ServeMux{serveMux: http.DefaultServeMux}
// DefaultServeMux returns a [ServeMux] containing [http.DefaultServeMux].
func DefaultServeMux() *ServeMux { return &defaultServeMux }
// HandlerRoute uses [http.ServeMux.Handler] to return a [Route] containing the
// handler and pattern to use for the given [http.Request].
func (mux *ServeMux) HandlerRoute(req *http.Request) Route {
h, pattern := mux.Handler(req)
if r, ok := h.(Route); ok {
return r
}
return Route{
Pattern: pattern,
Handler: h,
}
}
// HandleRoute registers a route to the [ServeMux] using its internal
// [http.ServeMux.Handle].
func (mux *ServeMux) HandleRoute(route Route) {
mux.Handle(route.Method+" "+route.Pattern, route.GetHandler())
}
// NotFoundHandler returns the [http.Handler] set with
// [ServeMux.WithNotFoundHandler].
func (mux *ServeMux) NotFoundHandler() http.Handler {
mux.mut.RLock()
defer mux.mut.RUnlock()
return mux.notFound
}
// WithNotFoundHandler sets a [http.Handler] which is called when there is no
// matching pattern. If not set, [ServeMux] will use the internal
// [http.ServeMux]'s default not found handler, which is [http.NotFound].
func (mux *ServeMux) WithNotFoundHandler(h http.Handler) *ServeMux {
mux.mut.Lock()
mux.notFound = h
mux.mut.Unlock()
return mux
}
func (mux *ServeMux) ServeHTTP(wri http.ResponseWriter, req *http.Request) {
// below if-statement is taken from the http.ServeMux.ServeHTTP method
if req.RequestURI == "*" {
if req.ProtoAtLeast(1, 1) {
wri.Header().Set("Connection", "close")
}
wri.WriteHeader(http.StatusBadRequest)
return
}
notFound := mux.NotFoundHandler()
h, pattern := mux.Handler(req)
if notFound != nil && pattern == "" {
notFound.ServeHTTP(wri, req)
return
}
//todo: req.SetPathValue()
req.Pattern = pattern
h.ServeHTTP(wri, req)
}
func (mux *ServeMux) apply(srv *Server) error {
srv.Handler = mux
return nil
}