Prepare for custom child router(s) via plugin(s) for tomorrow

This commit is contained in:
Makis Maropoulos 2016-07-07 23:59:00 +02:00
parent e3b2c68085
commit 52099314e6
5 changed files with 117 additions and 15 deletions

View File

@ -68,6 +68,40 @@ func (s *Framework) CloseWithErr() error {
return s.Close()
}
// MustUse registers Handler middleware to the beginning, prepends them instead of append
// DEPRECATED: use UseGlobal instead
// Use it when you want to add a global middleware to all parties, to all routes in all subdomains
// It can be called after other, (but before .Listen of course)
func MustUse(handlers ...Handler) {
Default.MustUse(handlers...)
}
// MustUseFunc registers HandlerFunc middleware to the beginning, prepends them instead of append
// DEPRECATED: use UseGlobalFunc instead
// Use it when you want to add a global middleware to all parties, to all routes in all subdomains
// It can be called after other, (but before .Listen of course)
func MustUseFunc(handlersFn ...HandlerFunc) {
Default.MustUseFunc(handlersFn...)
}
// MustUse registers Handler middleware to the beginning, prepends them instead of append
// DEPRECATED: use UseGlobal instead
// Use it when you want to add a global middleware to all parties, to all routes in all subdomains
// It can be called after other, (but before .Listen of course)
func (s *Framework) MustUse(handlers ...Handler) {
for _, r := range s.mux.lookups {
r.middleware = append(handlers, r.middleware...)
}
}
// MustUseFunc registers HandlerFunc middleware to the beginning, prepends them instead of append
// DEPRECATED: use UseGlobalFunc instead
// Use it when you want to add a global middleware to all parties, to all routes in all subdomains
// It can be called after other, (but before .Listen of course)
func (s *Framework) MustUseFunc(handlersFn ...HandlerFunc) {
s.MustUse(convertToHandlers(handlersFn)...)
}
// PostFormMulti returns a slice of string from post request's data
// DEPRECATED: Plase use FormValues instead
func (ctx *Context) PostFormMulti(name string) []string {

26
http.go
View File

@ -315,14 +315,19 @@ func (s *Server) Port() (port int) {
return
}
// FullHost returns the scheme+host
func (s *Server) FullHost() string {
// Scheme returns http:// or https:// if SSL is enabled
func (s *Server) Scheme() string {
scheme := "http://"
// we need to be able to take that before(for testing &debugging) and after server's listen
if s.IsSecure() || (s.Config.CertFile != "" && s.Config.KeyFile != "") {
scheme = "https://"
}
return scheme + s.Host()
return scheme
}
// FullHost returns the scheme+host
func (s *Server) FullHost() string {
return s.Scheme() + s.Host()
}
// Hostname returns the hostname part of the host (host expect port)
@ -850,7 +855,7 @@ func (e *muxEntry) add(path string, middleware Middleware) error {
if len(path) >= len(e.part) && e.part == path[:len(e.part)] {
if len(e.part) >= len(path) || path[len(e.part)] == '/' {
if len(e.part) >= len(path) || path[len(e.part)] == slashByte {
continue loop
}
}
@ -859,7 +864,7 @@ func (e *muxEntry) add(path string, middleware Middleware) error {
c := path[0]
if e.entryCase == hasParams && c == '/' && len(e.nodes) == 1 {
if e.entryCase == hasParams && c == slashByte && len(e.nodes) == 1 {
e = e.nodes[0]
e.precedence++
continue loop
@ -1148,6 +1153,8 @@ type (
Method() string
// Path returns the path
Path() string
// SetPath changes/sets the path for the Route
SetPath(string)
// Middleware returns the slice of Handler([]Handler) registed to this route
Middleware() Middleware
}
@ -1239,6 +1246,10 @@ func (r route) Path() string {
return r.path
}
func (r *route) SetPath(s string) {
r.path = s
}
func (r route) Middleware() Middleware {
return r.middleware
}
@ -1265,6 +1276,8 @@ type (
tree *muxTree
lookups []*route
onLookup func(Route)
api *muxAPI
errorHandlers map[int]Handler
logger *logger.Logger
@ -1360,6 +1373,9 @@ func (mux *serveMux) register(method []byte, subdomain string, path string, midd
// add to the lookups, it's just a collection of routes information
lookup := newRoute(method, subdomain, path, middleware)
if mux.onLookup != nil {
mux.onLookup(lookup)
}
mux.lookups = append(mux.lookups, lookup)
return lookup

View File

@ -103,6 +103,24 @@ func TestServerHostname(t *testing.T) {
}
}
func TestServerFullHost(t *testing.T) {
var server1 Server
var server2 Server
server1.Config.ListeningAddr = "127.0.0.1:8080"
server1.Config.CertFile = "notempty"
server1.Config.KeyFile = "notempty"
server2.Config.ListeningAddr = "127.0.0.1:8080"
server1ExpectingFullhost := "https://" + server1.Config.ListeningAddr
server2ExpectingFullhost := "http://" + server2.Config.ListeningAddr
if server1.FullHost() != server1ExpectingFullhost {
t.Fatalf("Expecting server 1's fullhost to be %s but got %s", server1ExpectingFullhost, server1.FullHost())
}
if server2.FullHost() != server2ExpectingFullhost {
t.Fatalf("Expecting server 2's fullhost to be %s but got %s", server2ExpectingFullhost, server2.FullHost())
}
}
func TestServerPort(t *testing.T) {
var server1, server2 Server
expectedPort1 := 8080

23
iris.go
View File

@ -165,8 +165,12 @@ type (
Go() error
Close() error
// global middleware prepending, registers to all subdomains, to all parties, you can call it at the last also
// deprecated Start
MustUse(...Handler)
MustUseFunc(...HandlerFunc)
// deprecated End
UseGlobal(...Handler)
UseGlobalFunc(...HandlerFunc)
OnError(int, HandlerFunc)
EmitError(int, *Context)
Lookup(string) Route
@ -220,6 +224,7 @@ func New(cfg ...config.Iris) *Framework {
s.Websocket = websocket.NewServer(s.Config.Websocket)
// set the servemux, which will provide us the public API also, with its context pool
mux := newServeMux(sync.Pool{New: func() interface{} { return &Context{framework: s} }}, s.Logger)
mux.onLookup = s.Plugins.DoPreLookup
// set the public router API (and party)
s.muxAPI = &muxAPI{mux: mux, relativePath: "/"}
@ -247,7 +252,6 @@ func (s *Framework) initialize() {
// prepare the mux & the server
s.mux.setCorrectPath(!s.Config.DisablePathCorrection)
s.mux.setEscapePath(!s.Config.DisablePathEscape)
// set the debug profiling handlers if ProfilePath is setted
if debugPath := s.Config.ProfilePath; debugPath != "" {
s.Handle(MethodGet, debugPath+"/*action", profileMiddleware(debugPath)...)
@ -479,37 +483,37 @@ func (s *Framework) Close() error {
return s.Servers.CloseAll()
}
// MustUse registers Handler middleware to the beginning, prepends them instead of append
// UseGlobal registers Handler middleware to the beginning, prepends them instead of append
//
// Use it when you want to add a global middleware to all parties, to all routes in all subdomains
// It can be called after other, (but before .Listen of course)
func MustUse(handlers ...Handler) {
func UseGlobal(handlers ...Handler) {
Default.MustUse(handlers...)
}
// MustUseFunc registers HandlerFunc middleware to the beginning, prepends them instead of append
// UseGlobalFunc registers HandlerFunc middleware to the beginning, prepends them instead of append
//
// Use it when you want to add a global middleware to all parties, to all routes in all subdomains
// It can be called after other, (but before .Listen of course)
func MustUseFunc(handlersFn ...HandlerFunc) {
func UseGlobalFunc(handlersFn ...HandlerFunc) {
Default.MustUseFunc(handlersFn...)
}
// MustUse registers Handler middleware to the beginning, prepends them instead of append
// UseGlobal registers Handler middleware to the beginning, prepends them instead of append
//
// Use it when you want to add a global middleware to all parties, to all routes in all subdomains
// It can be called after other, (but before .Listen of course)
func (s *Framework) MustUse(handlers ...Handler) {
func (s *Framework) UseGlobal(handlers ...Handler) {
for _, r := range s.mux.lookups {
r.middleware = append(handlers, r.middleware...)
}
}
// MustUseFunc registers HandlerFunc middleware to the beginning, prepends them instead of append
// UseGlobalFunc registers HandlerFunc middleware to the beginning, prepends them instead of append
//
// Use it when you want to add a global middleware to all parties, to all routes in all subdomains
// It can be called after other, (but before .Listen of course)
func (s *Framework) MustUseFunc(handlersFn ...HandlerFunc) {
func (s *Framework) UseGlobalFunc(handlersFn ...HandlerFunc) {
s.MustUse(convertToHandlers(handlersFn)...)
}
@ -914,6 +918,7 @@ func (api *muxAPI) Handle(method string, registedPath string, handlers ...Handle
}
path = strings.Replace(path, "//", "/", -1) // fix the path if double //
return api.mux.register([]byte(method), subdomain, path, middleware).setName
}

View File

@ -53,6 +53,13 @@ type (
// PluginContainer parameter used to add other plugins if that's necessary by the plugin
Activate(PluginContainer) error
}
// pluginPreLookup implements the PreRoute(Route) method
pluginPreLookup interface {
// PreLookup called before register a route
PreLookup(Route)
}
// PreLookupFunc implements the simple function listener for the PreLookup(Route)
PreLookupFunc func(Route)
// pluginPreListen implements the PreListen(*Framework) method
pluginPreListen interface {
// PreListen it's being called only one time, BEFORE the Server is started (if .Listen called)
@ -105,6 +112,8 @@ type (
GetDescription(Plugin) string
GetByName(string) Plugin
Printf(string, ...interface{})
PreLookup(PreLookupFunc)
DoPreLookup(Route)
PreListen(PreListenFunc)
DoPreListen(*Framework)
DoPreListenParallel(*Framework)
@ -148,6 +157,11 @@ type (
// convert the functions to plugin
// PreLookup called before register a route
func (fn PreLookupFunc) PreLookup(r Route) {
fn(r)
}
// PreListen it's being called only one time, BEFORE the Server is started (if .Listen called)
// is used to do work at the time all other things are ready to go
// parameter is the station
@ -339,12 +353,27 @@ func (p *pluginContainer) Printf(format string, a ...interface{}) {
}
// PreLookup adds a PreLookup plugin-function to the plugin flow container
func (p *pluginContainer) PreLookup(fn PreLookupFunc) {
p.Add(fn)
}
// DoPreLookup raise all plugins which has the PreLookup method
func (p *pluginContainer) DoPreLookup(r Route) {
for i := range p.activatedPlugins {
// check if this method exists on our plugin obj, these are optionaly and call it
if pluginObj, ok := p.activatedPlugins[i].(pluginPreLookup); ok {
pluginObj.PreLookup(r)
}
}
}
// PreListen adds a PreListen plugin-function to the plugin flow container
func (p *pluginContainer) PreListen(fn PreListenFunc) {
p.Add(fn)
}
// DoPreListen raise all plugins which has the DoPreListen method
// DoPreListen raise all plugins which has the PreListen method
func (p *pluginContainer) DoPreListen(station *Framework) {
for i := range p.activatedPlugins {
// check if this method exists on our plugin obj, these are optionaly and call it