@@ -32,6 +32,7 @@ type ServerConfig struct {
32
32
// Server represents a web.go server.
33
33
type Server struct {
34
34
Config * ServerConfig
35
+ middleware []reflect.Value
35
36
routes []route
36
37
Logger * log.Logger
37
38
Env map [string ]interface {}
@@ -61,27 +62,44 @@ type route struct {
61
62
r string
62
63
cr * regexp.Regexp
63
64
method string
64
- handler reflect.Value
65
+ handlers [] reflect.Value
65
66
httpHandler http.Handler
66
67
}
67
68
68
- func (s * Server ) addRoute (r string , method string , handler interface {}) {
69
+ func (s * Server ) addRoute (r string , method string , handlers ... interface {}) {
69
70
cr , err := regexp .Compile (r )
70
71
if err != nil {
71
72
s .Logger .Printf ("Error in route regex %q\n " , r )
72
73
return
73
74
}
74
75
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
84
100
}
101
+
102
+ s .routes = append (s .routes , route {r : r , cr : cr , method : method , httpHandler : handler .(http.Handler )})
85
103
}
86
104
87
105
// 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) {
98
116
}
99
117
100
118
// 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 ... )
103
121
}
104
122
105
123
// 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 ... )
108
126
}
109
127
110
128
// 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 ... )
113
131
}
114
132
115
133
// 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 ... )
118
136
}
119
137
120
138
// 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 ... )
123
141
}
124
142
125
143
//Adds a custom handler. Only for webserver mode. Will have no effect when running as FCGI or SCGI.
126
144
func (s * Server ) Handler (route string , method string , httpHandler http.Handler ) {
127
- s .addRoute (route , method , httpHandler )
145
+ s .addHandler (route , method , httpHandler )
128
146
}
129
147
130
148
//Adds a handler for websockets. Only for webserver mode. Will have no effect when running as FCGI or SCGI.
131
149
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
+ }
133
161
}
134
162
135
163
// Run starts the web application and serves HTTP requests for s
@@ -298,8 +326,31 @@ func (s *Server) logRequest(ctx Context, sTime time.Time) {
298
326
// route. The caller is then responsible for calling the httpHandler associated
299
327
// with the returned route.
300
328
func (s * Server ) routeHandler (req * http.Request , w http.ResponseWriter ) (unused * route ) {
329
+ routeHit := false
301
330
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
+ }
303
354
304
355
//set some default headers
305
356
ctx .SetHeader ("Server" , "web.go" , true )
@@ -313,6 +364,7 @@ func (s *Server) routeHandler(req *http.Request, w http.ResponseWriter) (unused
313
364
}
314
365
}
315
366
367
+ defer finishResponse ()
316
368
defer s .logRequest (ctx , tm )
317
369
318
370
ctx .SetHeader ("Date" , webTime (tm ), true )
@@ -326,9 +378,20 @@ func (s *Server) routeHandler(req *http.Request, w http.ResponseWriter) (unused
326
378
//Set the default content-type
327
379
ctx .SetHeader ("Content-Type" , "text/html; charset=utf-8" , true )
328
380
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
+
329
391
for i := 0 ; i < len (s .routes ); i ++ {
330
392
route := s .routes [i ]
331
393
cr := route .cr
394
+
332
395
//if the methods don't match, skip this handler (except HEAD can be used in place of GET)
333
396
if req .Method != route .method && ! (req .Method == "HEAD" && route .method == "GET" ) {
334
397
continue
@@ -337,6 +400,7 @@ func (s *Server) routeHandler(req *http.Request, w http.ResponseWriter) (unused
337
400
if ! cr .MatchString (requestPath ) {
338
401
continue
339
402
}
403
+
340
404
match := cr .FindStringSubmatch (requestPath )
341
405
342
406
if len (match [0 ]) != len (requestPath ) {
@@ -349,51 +413,67 @@ func (s *Server) routeHandler(req *http.Request, w http.ResponseWriter) (unused
349
413
return
350
414
}
351
415
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 )
360
420
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
+ }
365
424
}
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
+ }
368
435
}
369
436
370
- sval := ret [0 ]
437
+ ctx .Abort (404 , "Page not found" )
438
+ }
371
439
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 ]
372
465
var content []byte
373
466
374
467
if sval .Kind () == reflect .String {
375
468
content = []byte (sval .String ())
376
469
} else if sval .Kind () == reflect .Slice && sval .Type ().Elem ().Kind () == reflect .Uint8 {
377
470
content = sval .Interface ().([]byte )
378
471
}
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
- }
386
472
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 ()
394
474
}
395
- ctx . Abort ( 404 , "Page not found" )
396
- return
475
+
476
+ return make ([] byte , 0 ), ctx . IsFinished ()
397
477
}
398
478
399
479
// SetLogger sets the logger for server s
0 commit comments