aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/emicklei/go-restful/container.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/emicklei/go-restful/container.go')
-rw-r--r--vendor/github.com/emicklei/go-restful/container.go126
1 files changed, 77 insertions, 49 deletions
diff --git a/vendor/github.com/emicklei/go-restful/container.go b/vendor/github.com/emicklei/go-restful/container.go
index 59f34abea..4196180e5 100644
--- a/vendor/github.com/emicklei/go-restful/container.go
+++ b/vendor/github.com/emicklei/go-restful/container.go
@@ -6,6 +6,7 @@ package restful
import (
"bytes"
+ "errors"
"fmt"
"net/http"
"os"
@@ -24,24 +25,24 @@ type Container struct {
ServeMux *http.ServeMux
isRegisteredOnRoot bool
containerFilters []FilterFunction
- doNotRecover bool // default is false
+ doNotRecover bool // default is true
recoverHandleFunc RecoverHandleFunction
serviceErrorHandleFunc ServiceErrorHandleFunction
- router RouteSelector // default is a RouterJSR311, CurlyRouter is the faster alternative
+ router RouteSelector // default is a CurlyRouter (RouterJSR311 is a slower alternative)
contentEncodingEnabled bool // default is false
}
-// NewContainer creates a new Container using a new ServeMux and default router (RouterJSR311)
+// NewContainer creates a new Container using a new ServeMux and default router (CurlyRouter)
func NewContainer() *Container {
return &Container{
webServices: []*WebService{},
ServeMux: http.NewServeMux(),
isRegisteredOnRoot: false,
containerFilters: []FilterFunction{},
- doNotRecover: false,
+ doNotRecover: true,
recoverHandleFunc: logStackOnRecover,
serviceErrorHandleFunc: writeServiceError,
- router: RouterJSR311{},
+ router: CurlyRouter{},
contentEncodingEnabled: false}
}
@@ -68,12 +69,12 @@ func (c *Container) ServiceErrorHandler(handler ServiceErrorHandleFunction) {
// DoNotRecover controls whether panics will be caught to return HTTP 500.
// If set to true, Route functions are responsible for handling any error situation.
-// Default value is false = recover from panics. This has performance implications.
+// Default value is true.
func (c *Container) DoNotRecover(doNot bool) {
c.doNotRecover = doNot
}
-// Router changes the default Router (currently RouterJSR311)
+// Router changes the default Router (currently CurlyRouter)
func (c *Container) Router(aRouter RouteSelector) {
c.router = aRouter
}
@@ -83,34 +84,16 @@ func (c *Container) EnableContentEncoding(enabled bool) {
c.contentEncodingEnabled = enabled
}
-// Add a WebService to the Container. It will detect duplicate root paths and panic in that case.
+// Add a WebService to the Container. It will detect duplicate root paths and exit in that case.
func (c *Container) Add(service *WebService) *Container {
c.webServicesLock.Lock()
defer c.webServicesLock.Unlock()
- // If registered on root then no additional specific mapping is needed
- if !c.isRegisteredOnRoot {
- pattern := c.fixedPrefixPath(service.RootPath())
- // check if root path registration is needed
- if "/" == pattern || "" == pattern {
- c.ServeMux.HandleFunc("/", c.dispatch)
- c.isRegisteredOnRoot = true
- } else {
- // detect if registration already exists
- alreadyMapped := false
- for _, each := range c.webServices {
- if each.RootPath() == service.RootPath() {
- alreadyMapped = true
- break
- }
- }
- if !alreadyMapped {
- c.ServeMux.HandleFunc(pattern, c.dispatch)
- if !strings.HasSuffix(pattern, "/") {
- c.ServeMux.HandleFunc(pattern+"/", c.dispatch)
- }
- }
- }
+
+ // if rootPath was not set then lazy initialize it
+ if len(service.rootPath) == 0 {
+ service.Path("/")
}
+
// cannot have duplicate root paths
for _, each := range c.webServices {
if each.RootPath() == service.RootPath() {
@@ -118,24 +101,64 @@ func (c *Container) Add(service *WebService) *Container {
os.Exit(1)
}
}
- // if rootPath was not set then lazy initialize it
- if len(service.rootPath) == 0 {
- service.Path("/")
+
+ // If not registered on root then add specific mapping
+ if !c.isRegisteredOnRoot {
+ c.isRegisteredOnRoot = c.addHandler(service, c.ServeMux)
}
c.webServices = append(c.webServices, service)
return c
}
+// addHandler may set a new HandleFunc for the serveMux
+// this function must run inside the critical region protected by the webServicesLock.
+// returns true if the function was registered on root ("/")
+func (c *Container) addHandler(service *WebService, serveMux *http.ServeMux) bool {
+ pattern := fixedPrefixPath(service.RootPath())
+ // check if root path registration is needed
+ if "/" == pattern || "" == pattern {
+ serveMux.HandleFunc("/", c.dispatch)
+ return true
+ }
+ // detect if registration already exists
+ alreadyMapped := false
+ for _, each := range c.webServices {
+ if each.RootPath() == service.RootPath() {
+ alreadyMapped = true
+ break
+ }
+ }
+ if !alreadyMapped {
+ serveMux.HandleFunc(pattern, c.dispatch)
+ if !strings.HasSuffix(pattern, "/") {
+ serveMux.HandleFunc(pattern+"/", c.dispatch)
+ }
+ }
+ return false
+}
+
func (c *Container) Remove(ws *WebService) error {
+ if c.ServeMux == http.DefaultServeMux {
+ errMsg := fmt.Sprintf("[restful] cannot remove a WebService from a Container using the DefaultServeMux: ['%v']", ws)
+ log.Print(errMsg)
+ return errors.New(errMsg)
+ }
c.webServicesLock.Lock()
defer c.webServicesLock.Unlock()
+ // build a new ServeMux and re-register all WebServices
+ newServeMux := http.NewServeMux()
newServices := []*WebService{}
- for ix := range c.webServices {
- if c.webServices[ix].rootPath != ws.rootPath {
- newServices = append(newServices, c.webServices[ix])
+ newIsRegisteredOnRoot := false
+ for _, each := range c.webServices {
+ if each.rootPath != ws.rootPath {
+ // If not registered on root then add specific mapping
+ if !newIsRegisteredOnRoot {
+ newIsRegisteredOnRoot = c.addHandler(each, newServeMux)
+ }
+ newServices = append(newServices, each)
}
}
- c.webServices = newServices
+ c.webServices, c.ServeMux, c.isRegisteredOnRoot = newServices, newServeMux, newIsRegisteredOnRoot
return nil
}
@@ -166,6 +189,17 @@ func writeServiceError(err ServiceError, req *Request, resp *Response) {
}
// Dispatch the incoming Http Request to a matching WebService.
+func (c *Container) Dispatch(httpWriter http.ResponseWriter, httpRequest *http.Request) {
+ if httpWriter == nil {
+ panic("httpWriter cannot be nil")
+ }
+ if httpRequest == nil {
+ panic("httpRequest cannot be nil")
+ }
+ c.dispatch(httpWriter, httpRequest)
+}
+
+// Dispatch the incoming Http Request to a matching WebService.
func (c *Container) dispatch(httpWriter http.ResponseWriter, httpRequest *http.Request) {
writer := httpWriter
@@ -185,12 +219,6 @@ func (c *Container) dispatch(httpWriter http.ResponseWriter, httpRequest *http.R
}
}()
}
- // Install closing the request body (if any)
- defer func() {
- if nil != httpRequest.Body {
- httpRequest.Body.Close()
- }
- }()
// Detect if compression is needed
// assume without compression, test for override
@@ -251,7 +279,7 @@ func (c *Container) dispatch(httpWriter http.ResponseWriter, httpRequest *http.R
}
// fixedPrefixPath returns the fixed part of the partspec ; it may include template vars {}
-func (c Container) fixedPrefixPath(pathspec string) string {
+func fixedPrefixPath(pathspec string) string {
varBegin := strings.Index(pathspec, "{")
if -1 == varBegin {
return pathspec
@@ -260,12 +288,12 @@ func (c Container) fixedPrefixPath(pathspec string) string {
}
// ServeHTTP implements net/http.Handler therefore a Container can be a Handler in a http.Server
-func (c Container) ServeHTTP(httpwriter http.ResponseWriter, httpRequest *http.Request) {
+func (c *Container) ServeHTTP(httpwriter http.ResponseWriter, httpRequest *http.Request) {
c.ServeMux.ServeHTTP(httpwriter, httpRequest)
}
// Handle registers the handler for the given pattern. If a handler already exists for pattern, Handle panics.
-func (c Container) Handle(pattern string, handler http.Handler) {
+func (c *Container) Handle(pattern string, handler http.Handler) {
c.ServeMux.Handle(pattern, handler)
}
@@ -295,7 +323,7 @@ func (c *Container) Filter(filter FilterFunction) {
}
// RegisteredWebServices returns the collections of added WebServices
-func (c Container) RegisteredWebServices() []*WebService {
+func (c *Container) RegisteredWebServices() []*WebService {
c.webServicesLock.RLock()
defer c.webServicesLock.RUnlock()
result := make([]*WebService, len(c.webServices))
@@ -306,7 +334,7 @@ func (c Container) RegisteredWebServices() []*WebService {
}
// computeAllowedMethods returns a list of HTTP methods that are valid for a Request
-func (c Container) computeAllowedMethods(req *Request) []string {
+func (c *Container) computeAllowedMethods(req *Request) []string {
// Go through all RegisteredWebServices() and all its Routes to collect the options
methods := []string{}
requestPath := req.Request.URL.Path