Skip to content

Commit 83937b3

Browse files
committed
add basic_auth and nocache middleware, improve 404, add Bytes func
1 parent 36224c1 commit 83937b3

File tree

17 files changed

+286
-138
lines changed

17 files changed

+286
-138
lines changed

README.org

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
)
1111

1212
func main() {
13-
r := forest.New()
13+
r := forest.New(forest.Debug())
1414
r.Use(middleware.Recover())
1515
r.Use(middleware.Logger())
1616
r.GET("/", func(c forest.Context) error {

context.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ package forest
33
import (
44
"net/http"
55
"net/url"
6+
"os"
7+
"path/filepath"
8+
"strings"
69
"sync"
710

811
"github.com/honmaple/forest/binder"
912
"github.com/honmaple/forest/render"
10-
"os"
11-
"path/filepath"
1213
)
1314

1415
type H map[string]interface{}
@@ -36,14 +37,15 @@ type Context interface {
3637
JSON(int, interface{}) error
3738
JSONP(int, string, interface{}) error
3839
HTML(int, string) error
40+
Bytes(int, []byte) error
3941
String(int, string, ...interface{}) error
4042
Blob(int, string, []byte) error
4143
Render(int, string, interface{}) error
4244
RenderWith(int, render.Renderer) error
4345
File(string) error
4446

4547
Status(int) error
46-
Redirect(int, string) error
48+
Redirect(int, string, ...interface{}) error
4749
}
4850

4951
type context struct {
@@ -158,6 +160,10 @@ func (c *context) JSONP(code int, callback string, data interface{}) error {
158160
return render.JSONP(c.response, code, callback, data)
159161
}
160162

163+
func (c *context) Bytes(code int, data []byte) error {
164+
return render.Bytes(c.response, code, data)
165+
}
166+
161167
func (c *context) String(code int, format string, args ...interface{}) error {
162168
return render.Text(c.response, code, sprintf(format, args...))
163169
}
@@ -171,10 +177,13 @@ func (c *context) Status(code int) error {
171177
return nil
172178
}
173179

174-
func (c *context) Redirect(code int, url string) error {
180+
func (c *context) Redirect(code int, url string, args ...interface{}) error {
175181
if code < 300 || code > 308 {
176182
return nil
177183
}
184+
if !strings.HasPrefix(url, "/") && !strings.Contains(url, "://") {
185+
url = c.route.Engine().URL(url, args...)
186+
}
178187
c.response.Header().Set("Location", url)
179188
c.response.WriteHeader(code)
180189
return nil
@@ -241,7 +250,7 @@ func (c *context) reset(r *http.Request, w http.ResponseWriter) {
241250
c.index = -1
242251
}
243252

244-
func NewContext(r *http.Request, w http.ResponseWriter) Context {
253+
func NewContext(r *http.Request, w http.ResponseWriter) *context {
245254
c := &context{response: NewResponse(w)}
246255
c.reset(r, w)
247256
return c

contrib/response/response.go

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package response
22

33
import (
44
"net/http"
5-
"sync"
65

76
"github.com/honmaple/forest"
87
)
@@ -39,18 +38,10 @@ type ListResponse struct {
3938
List interface{} `json:"list,omitempty"`
4039
}
4140

42-
var respPool = sync.Pool{
43-
New: func() interface{} {
44-
return &Response{
45-
Code: http.StatusOK,
46-
Message: http.StatusText(http.StatusOK),
47-
}
48-
},
49-
}
50-
5141
func New(code int, data ...interface{}) *Response {
52-
resp := respPool.Get().(*Response)
53-
resp.Code = code
42+
resp := &Response{
43+
Code: code,
44+
}
5445

5546
if len(data) == 0 {
5647
resp.Message = http.StatusText(code)

contrib/session/session.go

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ import (
1212
const sessionName = "_session"
1313

1414
type session struct {
15-
name string
16-
store sessions.Store
17-
session *sessions.Session
18-
request *http.Request
19-
writer http.ResponseWriter
20-
written bool
15+
name string
16+
store sessions.Store
17+
session *sessions.Session
18+
request *http.Request
19+
response http.ResponseWriter
20+
written bool
2121
}
2222

2323
func (s *session) Get(key interface{}) interface{} {
@@ -54,7 +54,7 @@ func (s *session) Flashes(vars ...string) []interface{} {
5454

5555
func (s *session) Save() error {
5656
if s.Written() {
57-
e := s.Session().Save(s.request, s.writer)
57+
e := s.Session().Save(s.request, s.response)
5858
if e == nil {
5959
s.written = false
6060
}
@@ -84,6 +84,13 @@ func (s *session) Written() bool {
8484
return s.written
8585
}
8686

87+
func (s *session) reset(r *http.Request, w http.ResponseWriter) {
88+
s.request = r
89+
s.response = w
90+
s.session = nil
91+
s.written = false
92+
}
93+
8794
func Session(c forest.Context) *session {
8895
s := c.Get(sessionName)
8996
if s == nil {
@@ -100,8 +107,7 @@ func Middleware(name string, store sessions.Store) forest.HandlerFunc {
100107
}
101108
return func(c forest.Context) error {
102109
s := sessionPool.Get().(*session)
103-
s.request = c.Request()
104-
s.writer = c.Response()
110+
s.reset(c.Request(), c.Response())
105111
defer sessionPool.Put(s)
106112

107113
c.Set(sessionName, s)

engine.go

Lines changed: 57 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ type (
1515
Engine struct {
1616
*rootGroup
1717
mu sync.Mutex
18-
pool sync.Pool
18+
contextPool sync.Pool
1919
router *Router
2020
notFoundRoute *Route
2121
methodNotAllowedRoute *Route
22-
Debug bool
22+
debug bool
2323
Server *http.Server
2424
}
2525
HandlerFunc func(Context) error
@@ -31,11 +31,14 @@ var (
3131
ErrMethodNotAllowed = NewError(http.StatusMethodNotAllowed)
3232
ErrInternalServerError = NewError(http.StatusInternalServerError)
3333

34+
NotFoundMessage = []byte(ErrNotFound.Error())
35+
MethodNotAllowedMessage = []byte(ErrMethodNotAllowed.Error())
36+
3437
NotFoundHandler = func(c Context) error {
35-
return ErrNotFound
38+
return c.Bytes(http.StatusNotFound, NotFoundMessage)
3639
}
3740
MethodNotAllowedHandler = func(c Context) error {
38-
return ErrMethodNotAllowed
41+
return c.Bytes(http.StatusMethodNotAllowed, MethodNotAllowedMessage)
3942
}
4043
ErrorHandler = func(err error, c Context) {
4144
if err == nil {
@@ -77,37 +80,64 @@ func debugPrint(msg string, args ...interface{}) {
7780
fmt.Fprint(os.Stdout, sprintf(msg, args...))
7881
}
7982

80-
func New() *Engine {
83+
type Option func(e *Engine)
84+
85+
func Debug() Option {
86+
return func(e *Engine) {
87+
e.debug = true
88+
}
89+
}
90+
91+
func New(opts ...Option) *Engine {
8192
e := &Engine{
82-
pool: sync.Pool{
83-
New: func() interface{} {
84-
return NewContext(nil, nil)
85-
},
86-
},
8793
router: newRouter(),
8894
}
8995
e.rootGroup = &Group{
9096
engine: e,
9197
middlewares: make([]HandlerFunc, 0),
9298
}
93-
e.Debug = true
99+
e.contextPool = sync.Pool{
100+
New: func() interface{} {
101+
return NewContext(nil, nil)
102+
},
103+
}
94104
e.Logger = newLogger()
95105
e.ErrorHandler = ErrorHandler
96106
e.NotFound(NotFoundHandler)
97107
e.MethodNotAllowed(MethodNotAllowedHandler)
108+
for _, opt := range opts {
109+
opt(e)
110+
}
98111
return e
99112
}
100113

101-
func NewHost(host string) *Engine {
102-
e := New()
103-
e.host = host
104-
return e
114+
func WrapHandler(h http.Handler) HandlerFunc {
115+
return func(c Context) error {
116+
h.ServeHTTP(c.Response(), c.Request())
117+
return nil
118+
}
105119
}
106120

107121
func (e *Engine) addRoute(route *Route) {
108122
e.router.Insert(route)
109123
}
110124

125+
func (e *Engine) URL(name string, args ...interface{}) string {
126+
if r := e.Route(name); r != nil {
127+
return r.URL(args...)
128+
}
129+
return ""
130+
}
131+
132+
func (e *Engine) Route(name string) *Route {
133+
for _, r := range e.router.routes {
134+
if r.Name == name {
135+
return r
136+
}
137+
}
138+
return nil
139+
}
140+
111141
func (e *Engine) Router() *Router {
112142
return e.router
113143
}
@@ -120,15 +150,6 @@ func (e *Engine) Routes() []*Route {
120150
return routes
121151
}
122152

123-
func (e *Engine) URL(name string, args ...interface{}) string {
124-
for _, r := range e.router.routes {
125-
if r.Name == name {
126-
return r.URL(args...)
127-
}
128-
}
129-
return ""
130-
}
131-
132153
func (e *Engine) Use(middlewares ...HandlerFunc) *Engine {
133154
e.rootGroup.Use(middlewares...)
134155
e.notFoundRoute.Handlers = append(e.middlewares, e.notFoundRoute.Last())
@@ -138,6 +159,7 @@ func (e *Engine) Use(middlewares ...HandlerFunc) *Engine {
138159

139160
func (e *Engine) Mount(prefix string, child *Engine) {
140161
for _, r := range child.Routes() {
162+
r.Host = child.host
141163
r.Path = prefix + r.Path
142164
r.Handlers = append(e.middlewares, r.Handlers...)
143165
e.addRoute(r)
@@ -171,10 +193,10 @@ func (e *Engine) MethodNotAllowed(h HandlerFunc) {
171193
e.methodNotAllowedRoute.Handlers[len(e.methodNotAllowedRoute.Handlers)-1] = h
172194
}
173195

174-
func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
175-
c := e.pool.Get().(*context)
196+
func (e *Engine) Context(w http.ResponseWriter, r *http.Request) *context {
197+
c := e.contextPool.Get().(*context)
176198
c.reset(r, w)
177-
defer e.pool.Put(c)
199+
defer e.contextPool.Put(c)
178200

179201
// path := r.URL.EscapedPath()
180202
// if path == "" {
@@ -193,11 +215,17 @@ func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
193215
} else {
194216
c.route = e.notFoundRoute
195217
}
196-
c.Next()
218+
return c
219+
}
220+
221+
func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
222+
e.Context(w, r).Next()
197223
}
198224

199225
func (e *Engine) configure(addr string) error {
200-
if e.Debug {
226+
e.mu.Lock()
227+
defer e.mu.Unlock()
228+
if e.debug {
201229
for _, r := range e.router.routes {
202230
debugPrint(r.String())
203231
}
@@ -211,16 +239,12 @@ func (e *Engine) configure(addr string) error {
211239
}
212240

213241
func (e *Engine) Start(addr string) error {
214-
e.mu.Lock()
215242
e.configure(addr)
216-
e.mu.Unlock()
217243
return e.Server.ListenAndServe()
218244
}
219245

220246
func (e *Engine) StartTLS(addr string, certFile, keyFile string) error {
221-
e.mu.Lock()
222247
e.configure(addr)
223-
e.mu.Unlock()
224248
return e.Server.ListenAndServeTLS(certFile, keyFile)
225249
}
226250

examples/benchmark/README.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@ goos: darwin
1111
goarch: amd64
1212
pkg: github.com/honmaple/forest/examples/benchmark
1313
cpu: Intel(R) Core(TM) i5-8279U CPU @ 2.40GHz
14-
BenchmarkEchoStatic-8 30968 32932 ns/op 2374 B/op 157 allocs/op
15-
BenchmarkEchoGitHubAPI-8 24879 49490 ns/op 3016 B/op 203 allocs/op
16-
BenchmarkEchoGplusAPI-8 445206 2623 ns/op 181 B/op 13 allocs/op
17-
BenchmarkEchoParseAPI-8 256200 4766 ns/op 343 B/op 26 allocs/op
18-
BenchmarkGinStatic-8 26940 43482 ns/op 11949 B/op 314 allocs/op
19-
BenchmarkGinGitHubAPI-8 19398 60057 ns/op 15512 B/op 406 allocs/op
20-
BenchmarkGinGplusAPI-8 350064 3465 ns/op 1035 B/op 26 allocs/op
21-
BenchmarkGinParseAPI-8 176620 6509 ns/op 2068 B/op 52 allocs/op
22-
BenchmarkForestStatic-8 24504 50018 ns/op 1963 B/op 157 allocs/op
23-
BenchmarkForestGitHubAPI-8 12926 91675 ns/op 9479 B/op 287 allocs/op
24-
BenchmarkForestGplusAPI-8 269132 4288 ns/op 455 B/op 17 allocs/op
25-
BenchmarkForestParseAPI-8 137349 8774 ns/op 1833 B/op 44 allocs/op
14+
BenchmarkEchoStatic-8 34522 32306 ns/op 2259 B/op 157 allocs/op
15+
BenchmarkEchoGitHubAPI-8 24789 48676 ns/op 3021 B/op 203 allocs/op
16+
BenchmarkEchoGplusAPI-8 429786 2746 ns/op 184 B/op 13 allocs/op
17+
BenchmarkEchoParseAPI-8 249092 4829 ns/op 347 B/op 26 allocs/op
18+
BenchmarkGinStatic-8 33598 33378 ns/op 8568 B/op 157 allocs/op
19+
BenchmarkGinGitHubAPI-8 24686 47990 ns/op 11148 B/op 203 allocs/op
20+
BenchmarkGinGplusAPI-8 432154 2747 ns/op 704 B/op 13 allocs/op
21+
BenchmarkGinParseAPI-8 220762 5131 ns/op 1405 B/op 26 allocs/op
22+
BenchmarkForestStatic-8 31146 37876 ns/op 3935 B/op 109 allocs/op
23+
BenchmarkForestGitHubAPI-8 29334 45882 ns/op 13428 B/op 52 allocs/op
24+
BenchmarkForestGplusAPI-8 569188 2224 ns/op 702 B/op 4 allocs/op
25+
BenchmarkForestParseAPI-8 242726 5070 ns/op 1722 B/op 14 allocs/op
2626
PASS
27-
ok github.com/honmaple/forest/examples/benchmark 18.706s
27+
ok github.com/honmaple/forest/examples/benchmark 17.770s
2828
```

0 commit comments

Comments
 (0)