From c5f0bb371138aa534950db8b554a39b70813e0de Mon Sep 17 00:00:00 2001 From: Edd Steel Date: Sat, 17 Feb 2018 17:33:21 -0800 Subject: [PATCH] Allow endpoints to handle OPTIONS/MethodNotFound themselves --- agent/http.go | 7 ++++--- agent/http_oss.go | 3 ++- agent/prepared_query_endpoint.go | 22 ++++++++++++++++++++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/agent/http.go b/agent/http.go index 8bb98b6570..8a3d78c0e0 100644 --- a/agent/http.go +++ b/agent/http.go @@ -243,13 +243,14 @@ func (s *HTTPServer) wrap(handler endpoint, methods []string) http.HandlerFunc { var obj interface{} - // respond appropriately to OPTIONS requests - if req.Method == "OPTIONS" { + // if this endpoint has declared methods, respond appropriately to OPTIONS requests. Otherwise let the endpoint handle that. + if req.Method == "OPTIONS" && len(methods) > 0 { addAllowHeader(append([]string{"OPTIONS"}, methods...)) return } - methodFound := false + // if this endpoint has declared methods, check the request method. Otherwise let the endpoint handle that. + methodFound := len(methods) == 0 for _, method := range methods { if method == req.Method { methodFound = true diff --git a/agent/http_oss.go b/agent/http_oss.go index 8135c223c9..f4ea138d87 100644 --- a/agent/http_oss.go +++ b/agent/http_oss.go @@ -59,7 +59,8 @@ func init() { registerEndpoint("/v1/operator/autopilot/configuration", []string{"GET", "PUT"}, (*HTTPServer).OperatorAutopilotConfiguration) registerEndpoint("/v1/operator/autopilot/health", []string{"GET"}, (*HTTPServer).OperatorServerHealth) registerEndpoint("/v1/query", []string{"GET", "POST"}, (*HTTPServer).PreparedQueryGeneral) - registerEndpoint("/v1/query/", []string{"GET", "PUT", "DELETE"}, (*HTTPServer).PreparedQuerySpecific) + // because prepared queries have more complex rules for allowed methods, handle that in the endpoint. + registerEndpoint("/v1/query/", []string{}, (*HTTPServer).PreparedQuerySpecific) registerEndpoint("/v1/session/create", []string{"PUT"}, (*HTTPServer).SessionCreate) registerEndpoint("/v1/session/destroy/", []string{"PUT"}, (*HTTPServer).SessionDestroy) registerEndpoint("/v1/session/renew/", []string{"PUT"}, (*HTTPServer).SessionRenew) diff --git a/agent/prepared_query_endpoint.go b/agent/prepared_query_endpoint.go index 0be0ea3ed9..532cf70f4a 100644 --- a/agent/prepared_query_endpoint.go +++ b/agent/prepared_query_endpoint.go @@ -228,9 +228,31 @@ func (s *HTTPServer) preparedQueryDelete(id string, resp http.ResponseWriter, re return nil, nil } +// PreparedQuerySpecificOptions handles OPTIONS requests to prepared query endpoints. +func (s *HTTPServer) preparedQuerySpecificOptions(resp http.ResponseWriter, req *http.Request) interface{} { + path := req.URL.Path + switch { + case strings.HasSuffix(path, "/execute"): + resp.Header().Add("Allow", strings.Join([]string{"OPTIONS", "GET"}, ",")) + return resp + + case strings.HasSuffix(path, "/explain"): + resp.Header().Add("Allow", strings.Join([]string{"OPTIONS", "GET"}, ",")) + return resp + + default: + resp.Header().Add("Allow", strings.Join([]string{"OPTIONS", "GET", "PUT", "DELETE"}, ",")) + return resp + } +} + // PreparedQuerySpecific handles all the prepared query requests specific to a // particular query. func (s *HTTPServer) PreparedQuerySpecific(resp http.ResponseWriter, req *http.Request) (interface{}, error) { + if req.Method == "OPTIONS" { + return s.preparedQuerySpecificOptions(resp, req), nil + } + path := req.URL.Path id := strings.TrimPrefix(path, "/v1/query/")