From bdd080a61668bdec070c98adef73feb65d24cf86 Mon Sep 17 00:00:00 2001 From: Gregory Fast Date: Fri, 15 Mar 2024 15:11:48 -0400 Subject: [PATCH 1/7] feat: Add optional HTTP Middleware function to StartSettings for serverimpl Problem --------------------- Traces for HTTP requests to the opamp-go server break, see https://github.com/open-telemetry/opamp-go/issues/253 Solution --------------------- - Add an HTTP Handler middleware function to `StartSettings` - If this function is configured, apply it in serverimpl's `Start` where the HTTP Handler is set - (add unit tests) Code review notes --------------------- - This is a step in addressing https://github.com/open-telemetry/opamp-go/issues/253 but mostly just for HTTP clients and requests. There is likely more to do for maintaining trace linkage through requests that come over websocket connections - I figured if users are using `Attach` instead of `Start`, they might have their own middleware configured for their HTTP server, so it makes more sense to hook this into `StartSettings` and the `Start` function --- server/server.go | 4 ++ server/serverimpl.go | 6 +- server/serverimpl_test.go | 124 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 1 deletion(-) diff --git a/server/server.go b/server/server.go index 066edf42..885db052 100644 --- a/server/server.go +++ b/server/server.go @@ -42,6 +42,10 @@ type StartSettings struct { // Server's TLS configuration. TLSConfig *tls.Config + + // HTTPMiddlewareFunc specifies middleware for HTTP messages received by the server. + // This function is optional to set. + HTTPMiddlewareFunc func(handlerFunc http.HandlerFunc) http.HandlerFunc } type HTTPHandlerFunc func(http.ResponseWriter, *http.Request) diff --git a/server/serverimpl.go b/server/serverimpl.go index 10b159c3..e7fa1e9a 100644 --- a/server/serverimpl.go +++ b/server/serverimpl.go @@ -82,7 +82,11 @@ func (s *server) Start(settings StartSettings) error { path = defaultOpAMPPath } - mux.HandleFunc(path, s.httpHandler) + if settings.HTTPMiddlewareFunc != nil { + mux.HandleFunc(path, settings.HTTPMiddlewareFunc(s.httpHandler)) + } else { + mux.HandleFunc(path, s.httpHandler) + } hs := &http.Server{ Handler: mux, diff --git a/server/serverimpl_test.go b/server/serverimpl_test.go index 071a99e1..081a1332 100644 --- a/server/serverimpl_test.go +++ b/server/serverimpl_test.go @@ -57,6 +57,31 @@ func TestServerStartStop(t *testing.T) { assert.NoError(t, err) } +func TestServerStartStopWithMiddleware(t *testing.T) { + var addedMiddleware atomic.Bool + assert.False(t, addedMiddleware.Load()) + + testHTTPMiddlewareFunc := func(handlerFunc http.HandlerFunc) http.HandlerFunc { + addedMiddleware.Store(true) + return func(writer http.ResponseWriter, request *http.Request) { + handlerFunc(writer, request) + } + } + + startSettings := &StartSettings{ + HTTPMiddlewareFunc: testHTTPMiddlewareFunc, + } + + srv := startServer(t, startSettings) + assert.True(t, addedMiddleware.Load()) + + err := srv.Start(*startSettings) + assert.ErrorIs(t, err, errAlreadyStarted) + + err = srv.Stop(context.Background()) + assert.NoError(t, err) +} + func TestServerAddrWithNonZeroPort(t *testing.T) { srv := New(&sharedinternal.NopLogger{}) require.NotNil(t, srv) @@ -830,6 +855,105 @@ func TestConnectionAllowsConcurrentWrites(t *testing.T) { } } +func TestServerCallsHTTPMiddlewareOverWebsocket(t *testing.T) { + middlewareCalled := int32(0) + + testHTTPMiddlewareFunc := func(handlerFunc http.HandlerFunc) http.HandlerFunc { + return func(writer http.ResponseWriter, request *http.Request) { + atomic.AddInt32(&middlewareCalled, 1) + handlerFunc(writer, request) + } + } + + callbacks := CallbacksStruct{ + OnConnectingFunc: func(request *http.Request) types.ConnectionResponse { + return types.ConnectionResponse{ + Accept: true, + ConnectionCallbacks: ConnectionCallbacksStruct{}, + } + }, + } + + // Start a Server + settings := &StartSettings{ + HTTPMiddlewareFunc: testHTTPMiddlewareFunc, + Settings: Settings{Callbacks: callbacks}, + } + srv := startServer(t, settings) + defer func() { + err := srv.Stop(context.Background()) + assert.NoError(t, err) + }() + + // Connect to the server, ensuring successful connection + conn, resp, err := dialClient(settings) + assert.NoError(t, err) + assert.NotNil(t, conn) + require.NotNil(t, resp) + assert.EqualValues(t, 101, resp.StatusCode) + + // Verify middleware was called once for the websocket connection + eventually(t, func() bool { return atomic.LoadInt32(&middlewareCalled) == int32(1) }) + assert.Equal(t, int32(1), atomic.LoadInt32(&middlewareCalled)) +} + +func TestServerCallsHTTPMiddlewareOverHTTP(t *testing.T) { + middlewareCalled := int32(0) + + testHTTPMiddlewareFunc := func(handlerFunc http.HandlerFunc) http.HandlerFunc { + return func(writer http.ResponseWriter, request *http.Request) { + atomic.AddInt32(&middlewareCalled, 1) + handlerFunc(writer, request) + } + } + + callbacks := CallbacksStruct{ + OnConnectingFunc: func(request *http.Request) types.ConnectionResponse { + return types.ConnectionResponse{ + Accept: true, + ConnectionCallbacks: ConnectionCallbacksStruct{}, + } + }, + } + + // Start a Server + settings := &StartSettings{ + HTTPMiddlewareFunc: testHTTPMiddlewareFunc, + Settings: Settings{Callbacks: callbacks}, + } + srv := startServer(t, settings) + defer func() { + err := srv.Stop(context.Background()) + assert.NoError(t, err) + }() + + // Send an AgentToServer message to the Server + sendMsg1 := protobufs.AgentToServer{InstanceUid: "01BX5ZZKBKACTAV9WEVGEMMVS1"} + serializedProtoBytes1, err := proto.Marshal(&sendMsg1) + require.NoError(t, err) + _, err = http.Post( + "http://"+settings.ListenEndpoint+settings.ListenPath, + contentTypeProtobuf, + bytes.NewReader(serializedProtoBytes1), + ) + require.NoError(t, err) + + // Send another AgentToServer message to the Server + sendMsg2 := protobufs.AgentToServer{InstanceUid: "01BX5ZZKBKACTAV9WEVGEMMVRZ"} + serializedProtoBytes2, err := proto.Marshal(&sendMsg2) + require.NoError(t, err) + _, err = http.Post( + "http://"+settings.ListenEndpoint+settings.ListenPath, + contentTypeProtobuf, + bytes.NewReader(serializedProtoBytes2), + ) + require.NoError(t, err) + + // Verify middleware was triggered for each HTTP call + eventually(t, func() bool { return atomic.LoadInt32(&middlewareCalled) == int32(2) }) + assert.Equal(t, int32(2), atomic.LoadInt32(&middlewareCalled)) +} + func BenchmarkSendToClient(b *testing.B) { clientConnections := []*websocket.Conn{} serverConnections := []types.Connection{} From ab39e09524fd502dde7326ac6cd47f4fcc3dd140 Mon Sep 17 00:00:00 2001 From: Gregory Fast Date: Fri, 15 Mar 2024 17:16:58 -0400 Subject: [PATCH 2/7] Update comment for the setting --- server/server.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/server.go b/server/server.go index 885db052..2fce0ec5 100644 --- a/server/server.go +++ b/server/server.go @@ -44,7 +44,8 @@ type StartSettings struct { TLSConfig *tls.Config // HTTPMiddlewareFunc specifies middleware for HTTP messages received by the server. - // This function is optional to set. + // Note that the function will be called once for websockets upon connecting and will + // be called for every HTTP request. This function is optional to set. HTTPMiddlewareFunc func(handlerFunc http.HandlerFunc) http.HandlerFunc } From 213856bb0a86edd3f72c1cd216df29fe96944e48 Mon Sep 17 00:00:00 2001 From: Gregory Fast Date: Wed, 20 Mar 2024 13:17:26 -0400 Subject: [PATCH 3/7] Refactor HTTP middleware and add example --- internal/examples/server/opampsrv/opampsrv.go | 2 + server/server.go | 4 +- server/serverimpl.go | 11 ++--- server/serverimpl_test.go | 44 +++++++++++-------- 4 files changed, 35 insertions(+), 26 deletions(-) diff --git a/internal/examples/server/opampsrv/opampsrv.go b/internal/examples/server/opampsrv/opampsrv.go index bc652738..683b0dab 100644 --- a/internal/examples/server/opampsrv/opampsrv.go +++ b/internal/examples/server/opampsrv/opampsrv.go @@ -11,6 +11,7 @@ import ( "github.com/open-telemetry/opamp-go/protobufs" "github.com/open-telemetry/opamp-go/server" "github.com/open-telemetry/opamp-go/server/types" + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" ) type Server struct { @@ -54,6 +55,7 @@ func (srv *Server) Start() { }, }, ListenEndpoint: "127.0.0.1:4320", + HTTPMiddleware: otelhttp.NewMiddleware("HTTP POST"), } tlsConfig, err := internal.CreateServerTLSConfig( "../../certs/certs/ca.cert.pem", diff --git a/server/server.go b/server/server.go index 2fce0ec5..46acff9f 100644 --- a/server/server.go +++ b/server/server.go @@ -43,10 +43,10 @@ type StartSettings struct { // Server's TLS configuration. TLSConfig *tls.Config - // HTTPMiddlewareFunc specifies middleware for HTTP messages received by the server. + // HTTPMiddleware specifies middleware for HTTP messages received by the server. // Note that the function will be called once for websockets upon connecting and will // be called for every HTTP request. This function is optional to set. - HTTPMiddlewareFunc func(handlerFunc http.HandlerFunc) http.HandlerFunc + HTTPMiddleware func(handler http.Handler) http.Handler } type HTTPHandlerFunc func(http.ResponseWriter, *http.Request) diff --git a/server/serverimpl.go b/server/serverimpl.go index e7fa1e9a..f82f6fd1 100644 --- a/server/serverimpl.go +++ b/server/serverimpl.go @@ -61,7 +61,7 @@ func (s *server) Attach(settings Settings) (HTTPHandlerFunc, ConnContext, error) s.wsUpgrader = websocket.Upgrader{ EnableCompression: settings.EnableCompression, } - return s.httpHandler, contextWithConn, nil + return s.ServeHTTP, contextWithConn, nil } func (s *server) Start(settings StartSettings) error { @@ -82,10 +82,11 @@ func (s *server) Start(settings StartSettings) error { path = defaultOpAMPPath } - if settings.HTTPMiddlewareFunc != nil { - mux.HandleFunc(path, settings.HTTPMiddlewareFunc(s.httpHandler)) + if settings.HTTPMiddleware != nil { + mux.Handle(path, settings.HTTPMiddleware(s)) + //mux.HandleFunc(path, settings.HTTPMiddlewareFunc(s.httpHandler)) } else { - mux.HandleFunc(path, s.httpHandler) + mux.HandleFunc(path, s.ServeHTTP) } hs := &http.Server{ @@ -155,7 +156,7 @@ func (s *server) Addr() net.Addr { return s.addr } -func (s *server) httpHandler(w http.ResponseWriter, req *http.Request) { +func (s *server) ServeHTTP(w http.ResponseWriter, req *http.Request) { var connectionCallbacks serverTypes.ConnectionCallbacks if s.settings.Callbacks != nil { resp := s.settings.Callbacks.OnConnecting(req) diff --git a/server/serverimpl_test.go b/server/serverimpl_test.go index 081a1332..f17263f7 100644 --- a/server/serverimpl_test.go +++ b/server/serverimpl_test.go @@ -61,15 +61,17 @@ func TestServerStartStopWithMiddleware(t *testing.T) { var addedMiddleware atomic.Bool assert.False(t, addedMiddleware.Load()) - testHTTPMiddlewareFunc := func(handlerFunc http.HandlerFunc) http.HandlerFunc { + testHTTPMiddleware := func(handler http.Handler) http.Handler { addedMiddleware.Store(true) - return func(writer http.ResponseWriter, request *http.Request) { - handlerFunc(writer, request) - } + return http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + handler.ServeHTTP(w, r) + }, + ) } startSettings := &StartSettings{ - HTTPMiddlewareFunc: testHTTPMiddlewareFunc, + HTTPMiddleware: testHTTPMiddleware, } srv := startServer(t, startSettings) @@ -858,11 +860,13 @@ func TestConnectionAllowsConcurrentWrites(t *testing.T) { func TestServerCallsHTTPMiddlewareOverWebsocket(t *testing.T) { middlewareCalled := int32(0) - testHTTPMiddlewareFunc := func(handlerFunc http.HandlerFunc) http.HandlerFunc { - return func(writer http.ResponseWriter, request *http.Request) { - atomic.AddInt32(&middlewareCalled, 1) - handlerFunc(writer, request) - } + testHTTPMiddleware := func(handler http.Handler) http.Handler { + return http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + atomic.AddInt32(&middlewareCalled, 1) + handler.ServeHTTP(w, r) + }, + ) } callbacks := CallbacksStruct{ @@ -876,8 +880,8 @@ func TestServerCallsHTTPMiddlewareOverWebsocket(t *testing.T) { // Start a Server settings := &StartSettings{ - HTTPMiddlewareFunc: testHTTPMiddlewareFunc, - Settings: Settings{Callbacks: callbacks}, + HTTPMiddleware: testHTTPMiddleware, + Settings: Settings{Callbacks: callbacks}, } srv := startServer(t, settings) defer func() { @@ -900,11 +904,13 @@ func TestServerCallsHTTPMiddlewareOverWebsocket(t *testing.T) { func TestServerCallsHTTPMiddlewareOverHTTP(t *testing.T) { middlewareCalled := int32(0) - testHTTPMiddlewareFunc := func(handlerFunc http.HandlerFunc) http.HandlerFunc { - return func(writer http.ResponseWriter, request *http.Request) { - atomic.AddInt32(&middlewareCalled, 1) - handlerFunc(writer, request) - } + testHTTPMiddleware := func(handler http.Handler) http.Handler { + return http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + atomic.AddInt32(&middlewareCalled, 1) + handler.ServeHTTP(w, r) + }, + ) } callbacks := CallbacksStruct{ @@ -918,8 +924,8 @@ func TestServerCallsHTTPMiddlewareOverHTTP(t *testing.T) { // Start a Server settings := &StartSettings{ - HTTPMiddlewareFunc: testHTTPMiddlewareFunc, - Settings: Settings{Callbacks: callbacks}, + HTTPMiddleware: testHTTPMiddleware, + Settings: Settings{Callbacks: callbacks}, } srv := startServer(t, settings) defer func() { From dca20762b3313e3500e8ab3b625301152228abfb Mon Sep 17 00:00:00 2001 From: Gregory Fast Date: Wed, 20 Mar 2024 17:09:48 -0400 Subject: [PATCH 4/7] Finish adding example --- internal/examples/go.mod | 4 +++- internal/examples/go.sum | 4 ++++ internal/examples/server/opampsrv/opampsrv.go | 5 +++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/internal/examples/go.mod b/internal/examples/go.mod index cb4cf630..ee9dd117 100644 --- a/internal/examples/go.mod +++ b/internal/examples/go.mod @@ -9,6 +9,7 @@ require ( github.com/open-telemetry/opamp-go v0.1.0 github.com/shirou/gopsutil v3.21.11+incompatible github.com/stretchr/testify v1.8.4 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 go.opentelemetry.io/otel v1.24.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.24.0 go.opentelemetry.io/otel/metric v1.24.0 @@ -19,12 +20,13 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect - github.com/gorilla/websocket v1.5.1 // indirect github.com/golang/protobuf v1.5.3 // indirect + github.com/gorilla/websocket v1.5.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/mapstructure v1.4.1 // indirect diff --git a/internal/examples/go.sum b/internal/examples/go.sum index 237c4196..436276a8 100644 --- a/internal/examples/go.sum +++ b/internal/examples/go.sum @@ -21,6 +21,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= @@ -127,6 +129,8 @@ github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2bi github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.24.0 h1:mM8nKi6/iFQ0iqst80wDHU2ge198Ye/TfN0WBS5U24Y= diff --git a/internal/examples/server/opampsrv/opampsrv.go b/internal/examples/server/opampsrv/opampsrv.go index 683b0dab..49d6c01e 100644 --- a/internal/examples/server/opampsrv/opampsrv.go +++ b/internal/examples/server/opampsrv/opampsrv.go @@ -6,12 +6,13 @@ import ( "net/http" "os" + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" + "github.com/open-telemetry/opamp-go/internal" "github.com/open-telemetry/opamp-go/internal/examples/server/data" "github.com/open-telemetry/opamp-go/protobufs" "github.com/open-telemetry/opamp-go/server" "github.com/open-telemetry/opamp-go/server/types" - "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" ) type Server struct { @@ -55,7 +56,7 @@ func (srv *Server) Start() { }, }, ListenEndpoint: "127.0.0.1:4320", - HTTPMiddleware: otelhttp.NewMiddleware("HTTP POST"), + HTTPMiddleware: otelhttp.NewMiddleware("HTTP opamp-go"), } tlsConfig, err := internal.CreateServerTLSConfig( "../../certs/certs/ca.cert.pem", From 7608e11b18143f15d3021186e329f4bce73bdbac Mon Sep 17 00:00:00 2001 From: Gregory Fast Date: Wed, 20 Mar 2024 17:25:34 -0400 Subject: [PATCH 5/7] Remove comment and make mux calls match for middleware vs non-middleware --- server/serverimpl.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/serverimpl.go b/server/serverimpl.go index f82f6fd1..bc2a4792 100644 --- a/server/serverimpl.go +++ b/server/serverimpl.go @@ -84,9 +84,8 @@ func (s *server) Start(settings StartSettings) error { if settings.HTTPMiddleware != nil { mux.Handle(path, settings.HTTPMiddleware(s)) - //mux.HandleFunc(path, settings.HTTPMiddlewareFunc(s.httpHandler)) } else { - mux.HandleFunc(path, s.ServeHTTP) + mux.Handle(path, s) } hs := &http.Server{ From c186aaba8dbd32ce655e192f7d4569f8a007b163 Mon Sep 17 00:00:00 2001 From: Gregory Fast Date: Thu, 21 Mar 2024 11:37:26 -0400 Subject: [PATCH 6/7] Address feedback: HTTP operation name more closely follows semcov --- internal/examples/server/opampsrv/opampsrv.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/examples/server/opampsrv/opampsrv.go b/internal/examples/server/opampsrv/opampsrv.go index 49d6c01e..84bb2018 100644 --- a/internal/examples/server/opampsrv/opampsrv.go +++ b/internal/examples/server/opampsrv/opampsrv.go @@ -56,7 +56,7 @@ func (srv *Server) Start() { }, }, ListenEndpoint: "127.0.0.1:4320", - HTTPMiddleware: otelhttp.NewMiddleware("HTTP opamp-go"), + HTTPMiddleware: otelhttp.NewMiddleware("/v1/opamp"), } tlsConfig, err := internal.CreateServerTLSConfig( "../../certs/certs/ca.cert.pem", From 929e0d0c39c06abbf4fd18359e231e9c1635fb65 Mon Sep 17 00:00:00 2001 From: Gregory Fast Date: Thu, 21 Mar 2024 12:18:04 -0400 Subject: [PATCH 7/7] Wrap HTTP handler function in un-exported struct to avoid exporting ServerHTTP on the server struct --- server/serverimpl.go | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/server/serverimpl.go b/server/serverimpl.go index bc2a4792..2f5965a0 100644 --- a/server/serverimpl.go +++ b/server/serverimpl.go @@ -47,6 +47,16 @@ type server struct { var _ OpAMPServer = (*server)(nil) +// innerHTTPHandler implements the http.Handler interface so it can be used by functions +// that require the type (like Middleware) without exposing ServeHTTP directly on server. +type innerHTTPHander struct { + httpHandlerFunc http.HandlerFunc +} + +func (i innerHTTPHander) ServeHTTP(writer http.ResponseWriter, request *http.Request) { + i.httpHandlerFunc(writer, request) +} + // New creates a new OpAMP Server. func New(logger types.Logger) *server { if logger == nil { @@ -61,7 +71,7 @@ func (s *server) Attach(settings Settings) (HTTPHandlerFunc, ConnContext, error) s.wsUpgrader = websocket.Upgrader{ EnableCompression: settings.EnableCompression, } - return s.ServeHTTP, contextWithConn, nil + return s.httpHandler, contextWithConn, nil } func (s *server) Start(settings StartSettings) error { @@ -82,10 +92,12 @@ func (s *server) Start(settings StartSettings) error { path = defaultOpAMPPath } + handler := innerHTTPHander{s.httpHandler} + if settings.HTTPMiddleware != nil { - mux.Handle(path, settings.HTTPMiddleware(s)) + mux.Handle(path, settings.HTTPMiddleware(handler)) } else { - mux.Handle(path, s) + mux.Handle(path, handler) } hs := &http.Server{ @@ -155,7 +167,7 @@ func (s *server) Addr() net.Addr { return s.addr } -func (s *server) ServeHTTP(w http.ResponseWriter, req *http.Request) { +func (s *server) httpHandler(w http.ResponseWriter, req *http.Request) { var connectionCallbacks serverTypes.ConnectionCallbacks if s.settings.Callbacks != nil { resp := s.settings.Callbacks.OnConnecting(req)