Skip to content

Commit 4e6970f

Browse files
committed
Merge branch 'feature/middleware' into develop
2 parents 5a66d0f + 4aed38e commit 4e6970f

File tree

3 files changed

+202
-65
lines changed

3 files changed

+202
-65
lines changed

server.go

Lines changed: 135 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ type ServerConfig struct {
3232
// Server represents a web.go server.
3333
type Server struct {
3434
Config *ServerConfig
35+
middleware []reflect.Value
3536
routes []route
3637
Logger *log.Logger
3738
Env map[string]interface{}
@@ -61,27 +62,44 @@ type route struct {
6162
r string
6263
cr *regexp.Regexp
6364
method string
64-
handler reflect.Value
65+
handlers []reflect.Value
6566
httpHandler http.Handler
6667
}
6768

68-
func (s *Server) addRoute(r string, method string, handler interface{}) {
69+
func (s *Server) addRoute(r string, method string, handlers ...interface{}) {
6970
cr, err := regexp.Compile(r)
7071
if err != nil {
7172
s.Logger.Printf("Error in route regex %q\n", r)
7273
return
7374
}
7475

75-
switch handler.(type) {
76-
case http.Handler:
77-
s.routes = append(s.routes, route{r: r, cr: cr, method: method, httpHandler: handler.(http.Handler)})
78-
case reflect.Value:
79-
fv := handler.(reflect.Value)
80-
s.routes = append(s.routes, route{r: r, cr: cr, method: method, handler: fv})
81-
default:
82-
fv := reflect.ValueOf(handler)
83-
s.routes = append(s.routes, route{r: r, cr: cr, method: method, handler: fv})
76+
if len(handlers) == 0 {
77+
s.Logger.Printf("No handler specified for endpoint %s %s", method, r)
78+
return
79+
}
80+
81+
newHandlers := make([]reflect.Value, len(handlers), len(handlers))
82+
83+
for i, handler := range handlers {
84+
switch handler.(type) {
85+
case reflect.Value:
86+
newHandlers[i] = handler.(reflect.Value)
87+
default:
88+
newHandlers[i] = reflect.ValueOf(handler)
89+
}
90+
}
91+
92+
s.routes = append(s.routes, route{r: r, cr: cr, method: method, handlers: newHandlers})
93+
}
94+
95+
func (s *Server) addHandler(r string, method string, handler http.Handler) {
96+
cr, err := regexp.Compile(r)
97+
if err != nil {
98+
s.Logger.Printf("Error in route regex %q\n", r)
99+
return
84100
}
101+
102+
s.routes = append(s.routes, route{r: r, cr: cr, method: method, httpHandler: handler.(http.Handler)})
85103
}
86104

87105
// ServeHTTP is the interface method for Go's http server package
@@ -98,38 +116,48 @@ func (s *Server) Process(c http.ResponseWriter, req *http.Request) {
98116
}
99117

100118
// Get adds a handler for the 'GET' http method for server s.
101-
func (s *Server) Get(route string, handler interface{}) {
102-
s.addRoute(route, "GET", handler)
119+
func (s *Server) Get(route string, handlers ...interface{}) {
120+
s.addRoute(route, "GET", handlers...)
103121
}
104122

105123
// Post adds a handler for the 'POST' http method for server s.
106-
func (s *Server) Post(route string, handler interface{}) {
107-
s.addRoute(route, "POST", handler)
124+
func (s *Server) Post(route string, handlers ...interface{}) {
125+
s.addRoute(route, "POST", handlers...)
108126
}
109127

110128
// Put adds a handler for the 'PUT' http method for server s.
111-
func (s *Server) Put(route string, handler interface{}) {
112-
s.addRoute(route, "PUT", handler)
129+
func (s *Server) Put(route string, handlers ...interface{}) {
130+
s.addRoute(route, "PUT", handlers...)
113131
}
114132

115133
// Delete adds a handler for the 'DELETE' http method for server s.
116-
func (s *Server) Delete(route string, handler interface{}) {
117-
s.addRoute(route, "DELETE", handler)
134+
func (s *Server) Delete(route string, handlers ...interface{}) {
135+
s.addRoute(route, "DELETE", handlers...)
118136
}
119137

120138
// Match adds a handler for an arbitrary http method for server s.
121-
func (s *Server) Match(method string, route string, handler interface{}) {
122-
s.addRoute(route, method, handler)
139+
func (s *Server) Match(method string, route string, handlers ...interface{}) {
140+
s.addRoute(route, method, handlers...)
123141
}
124142

125143
//Adds a custom handler. Only for webserver mode. Will have no effect when running as FCGI or SCGI.
126144
func (s *Server) Handler(route string, method string, httpHandler http.Handler) {
127-
s.addRoute(route, method, httpHandler)
145+
s.addHandler(route, method, httpHandler)
128146
}
129147

130148
//Adds a handler for websockets. Only for webserver mode. Will have no effect when running as FCGI or SCGI.
131149
func (s *Server) Websocket(route string, httpHandler websocket.Handler) {
132-
s.addRoute(route, "GET", httpHandler)
150+
s.addHandler(route, "GET", httpHandler)
151+
}
152+
153+
// Adds a middleware to be called for all endpoints
154+
func (s *Server) Middleware(handler interface{}) {
155+
switch handler.(type) {
156+
case reflect.Value:
157+
s.middleware = append(s.middleware, handler.(reflect.Value))
158+
default:
159+
s.middleware = append(s.middleware, reflect.ValueOf(handler))
160+
}
133161
}
134162

135163
// Run starts the web application and serves HTTP requests for s
@@ -298,8 +326,31 @@ func (s *Server) logRequest(ctx Context, sTime time.Time) {
298326
// route. The caller is then responsible for calling the httpHandler associated
299327
// with the returned route.
300328
func (s *Server) routeHandler(req *http.Request, w http.ResponseWriter) (unused *route) {
329+
routeHit := false
301330
requestPath := req.URL.Path
302-
ctx := Context{req, map[string]string{}, s, w}
331+
allContent := make([][]byte, 0, 2)
332+
ctx := Context{req, map[string]string{}, s, w, false}
333+
334+
finishResponse := func() {
335+
if len(allContent) > 0 {
336+
contentLength := 0
337+
338+
for _, content := range allContent {
339+
contentLength += len(content)
340+
}
341+
342+
ctx.SetHeader("Content-Length", strconv.Itoa(contentLength), true)
343+
344+
for _, content := range allContent {
345+
_, err := ctx.ResponseWriter.Write(content)
346+
347+
if err != nil {
348+
ctx.Server.Logger.Println("Error during write: ", err)
349+
return
350+
}
351+
}
352+
}
353+
}
303354

304355
//set some default headers
305356
ctx.SetHeader("Server", "web.go", true)
@@ -313,6 +364,7 @@ func (s *Server) routeHandler(req *http.Request, w http.ResponseWriter) (unused
313364
}
314365
}
315366

367+
defer finishResponse()
316368
defer s.logRequest(ctx, tm)
317369

318370
ctx.SetHeader("Date", webTime(tm), true)
@@ -326,9 +378,20 @@ func (s *Server) routeHandler(req *http.Request, w http.ResponseWriter) (unused
326378
//Set the default content-type
327379
ctx.SetHeader("Content-Type", "text/html; charset=utf-8", true)
328380

381+
//Call the middleware
382+
for _, handler := range s.middleware {
383+
content, finished := s.callMiddleware(handler, ctx)
384+
allContent = append(allContent, content)
385+
386+
if finished {
387+
return
388+
}
389+
}
390+
329391
for i := 0; i < len(s.routes); i++ {
330392
route := s.routes[i]
331393
cr := route.cr
394+
332395
//if the methods don't match, skip this handler (except HEAD can be used in place of GET)
333396
if req.Method != route.method && !(req.Method == "HEAD" && route.method == "GET") {
334397
continue
@@ -337,6 +400,7 @@ func (s *Server) routeHandler(req *http.Request, w http.ResponseWriter) (unused
337400
if !cr.MatchString(requestPath) {
338401
continue
339402
}
403+
340404
match := cr.FindStringSubmatch(requestPath)
341405

342406
if len(match[0]) != len(requestPath) {
@@ -349,51 +413,67 @@ func (s *Server) routeHandler(req *http.Request, w http.ResponseWriter) (unused
349413
return
350414
}
351415

352-
var args []reflect.Value
353-
handlerType := route.handler.Type()
354-
if requiresContext(handlerType) {
355-
args = append(args, reflect.ValueOf(&ctx))
356-
}
357-
for _, arg := range match[1:] {
358-
args = append(args, reflect.ValueOf(arg))
359-
}
416+
for _, handler := range route.handlers {
417+
routeHit = true
418+
content, finished := s.callMiddleware(handler, ctx, match[1:]...)
419+
allContent = append(allContent, content)
360420

361-
ret, err := s.safelyCall(route.handler, args)
362-
if err != nil {
363-
//there was an error or panic while calling the handler
364-
ctx.Abort(500, "Server Error")
421+
if finished {
422+
return
423+
}
365424
}
366-
if len(ret) == 0 {
367-
return
425+
}
426+
427+
if !routeHit {
428+
// try serving index.html or index.htm
429+
if req.Method == "GET" || req.Method == "HEAD" {
430+
if s.tryServingFile(path.Join(requestPath, "index.html"), req, w) {
431+
return
432+
} else if s.tryServingFile(path.Join(requestPath, "index.htm"), req, w) {
433+
return
434+
}
368435
}
369436

370-
sval := ret[0]
437+
ctx.Abort(404, "Page not found")
438+
}
371439

440+
return
441+
}
442+
443+
func (s *Server) callMiddleware(handler reflect.Value, ctx Context, urlParts ...string) ([]byte, bool) {
444+
var args []reflect.Value
445+
handlerType := handler.Type()
446+
447+
if requiresContext(handlerType) {
448+
args = append(args, reflect.ValueOf(&ctx))
449+
}
450+
451+
for _, arg := range urlParts {
452+
args = append(args, reflect.ValueOf(arg))
453+
}
454+
455+
ret, err := s.safelyCall(handler, args)
456+
457+
if err != nil {
458+
//there was an error or panic while calling the handler
459+
ctx.Abort(500, "Server Error")
460+
return make([]byte, 0), true
461+
}
462+
463+
if ret != nil && len(ret) != 0 {
464+
sval := ret[0]
372465
var content []byte
373466

374467
if sval.Kind() == reflect.String {
375468
content = []byte(sval.String())
376469
} else if sval.Kind() == reflect.Slice && sval.Type().Elem().Kind() == reflect.Uint8 {
377470
content = sval.Interface().([]byte)
378471
}
379-
ctx.SetHeader("Content-Length", strconv.Itoa(len(content)), true)
380-
_, err = ctx.ResponseWriter.Write(content)
381-
if err != nil {
382-
ctx.Server.Logger.Println("Error during write: ", err)
383-
}
384-
return
385-
}
386472

387-
// try serving index.html or index.htm
388-
if req.Method == "GET" || req.Method == "HEAD" {
389-
if s.tryServingFile(path.Join(requestPath, "index.html"), req, w) {
390-
return
391-
} else if s.tryServingFile(path.Join(requestPath, "index.htm"), req, w) {
392-
return
393-
}
473+
return content, ctx.IsFinished()
394474
}
395-
ctx.Abort(404, "Page not found")
396-
return
475+
476+
return make([]byte, 0), ctx.IsFinished()
397477
}
398478

399479
// SetLogger sets the logger for server s

web.go

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ type Context struct {
3131
Params map[string]string
3232
Server *Server
3333
http.ResponseWriter
34+
finished bool
3435
}
3536

3637
// WriteString writes string data into the response object.
@@ -170,6 +171,14 @@ func (ctx *Context) GetSecureCookie(name string) (string, bool) {
170171
return "", false
171172
}
172173

174+
func (ctx *Context) IsFinished() bool {
175+
return ctx.finished
176+
}
177+
178+
func (ctx *Context) Finish() {
179+
ctx.finished = true
180+
}
181+
173182
// small optimization: cache the context type instead of repeteadly calling reflect.Typeof
174183
var contextType reflect.Type
175184

@@ -224,28 +233,28 @@ func Close() {
224233
}
225234

226235
// Get adds a handler for the 'GET' http method in the main server.
227-
func Get(route string, handler interface{}) {
228-
mainServer.Get(route, handler)
236+
func Get(route string, handlers ...interface{}) {
237+
mainServer.addRoute(route, "GET", handlers...)
229238
}
230239

231240
// Post adds a handler for the 'POST' http method in the main server.
232-
func Post(route string, handler interface{}) {
233-
mainServer.addRoute(route, "POST", handler)
241+
func Post(route string, handlers ...interface{}) {
242+
mainServer.addRoute(route, "POST", handlers...)
234243
}
235244

236245
// Put adds a handler for the 'PUT' http method in the main server.
237-
func Put(route string, handler interface{}) {
238-
mainServer.addRoute(route, "PUT", handler)
246+
func Put(route string, handlers ...interface{}) {
247+
mainServer.addRoute(route, "PUT", handlers...)
239248
}
240249

241250
// Delete adds a handler for the 'DELETE' http method in the main server.
242-
func Delete(route string, handler interface{}) {
243-
mainServer.addRoute(route, "DELETE", handler)
251+
func Delete(route string, handlers ...interface{}) {
252+
mainServer.addRoute(route, "DELETE", handlers...)
244253
}
245254

246255
// Match adds a handler for an arbitrary http method in the main server.
247-
func Match(method string, route string, handler interface{}) {
248-
mainServer.addRoute(route, method, handler)
256+
func Match(method string, route string, handlers ...interface{}) {
257+
mainServer.addRoute(route, method, handlers...)
249258
}
250259

251260
//Adds a custom handler. Only for webserver mode. Will have no effect when running as FCGI or SCGI.
@@ -258,6 +267,10 @@ func Websocket(route string, httpHandler websocket.Handler) {
258267
mainServer.Websocket(route, httpHandler)
259268
}
260269

270+
func Middleware(handler interface{}) {
271+
mainServer.Middleware(handler)
272+
}
273+
261274
// SetLogger sets the logger for the main server.
262275
func SetLogger(logger *log.Logger) {
263276
mainServer.Logger = logger

0 commit comments

Comments
 (0)