From 0779cc5869c37741015c4a3cd89ea5b6893c3e4f Mon Sep 17 00:00:00 2001 From: Rui Abreu Date: Mon, 3 Feb 2020 12:20:17 +0000 Subject: [PATCH] Changing the way the HTTP header Host is set --- core/internal/notifier/http.go | 11 +- core/internal/notifier/http_test.go | 206 +++++++++++++++++----------- 2 files changed, 133 insertions(+), 84 deletions(-) diff --git a/core/internal/notifier/http.go b/core/internal/notifier/http.go index 87660903..2e7ca08d 100644 --- a/core/internal/notifier/http.go +++ b/core/internal/notifier/http.go @@ -17,6 +17,7 @@ import ( "net" "net/http" "regexp" + "strings" "text/template" "time" @@ -202,8 +203,16 @@ func (module *HTTPNotifier) Notify(status *protocol.ConsumerGroupStatus, eventID } req.Header.Set("Content-Type", "application/json") - for header, value := range viper.GetStringMapString("notifier." + module.name + ".headers") { + headersMap := viper.GetStringMapString("notifier." + module.name + ".headers") + for header, value := range headersMap { req.Header.Set(header, value) + + // For client requests, Host optionally overrides the Host + // header to send. If empty, the Request.Write method uses + // the value of URL.Host + if strings.ToLower(header) == "host" && value != "" { + req.Host = value + } } resp, err := module.httpClient.Do(req) diff --git a/core/internal/notifier/http_test.go b/core/internal/notifier/http_test.go index 7d183417..3e0f50eb 100644 --- a/core/internal/notifier/http_test.go +++ b/core/internal/notifier/http_test.go @@ -14,6 +14,7 @@ import ( "encoding/json" "fmt" "net/http" + "strings" "text/template" "time" @@ -92,109 +93,148 @@ type HTTPRequest struct { Group string } +var notifyHTTPModuleTests = []struct { + ChangeHost bool +}{ + {false}, + {true}, +} + func TestHttpNotifier_Notify_Open(t *testing.T) { - // handler that validates that we get the right values - requestHandler := func(w http.ResponseWriter, r *http.Request) { - // Must get an appropriate Content-Type header - headers, ok := r.Header["Content-Type"] - assert.True(t, ok, "Expected to receive Content-Type header") - assert.Len(t, headers, 1, "Expected to receive exactly one Content-Type header") - assert.Equalf(t, "application/json", headers[0], "Expected Content-Type header to be 'application/json', not '%v'", headers[0]) - - tokenHeaders, ok := r.Header["Token"] - assert.True(t, ok, "Expected to receive Token header") - assert.Equalf(t, "testtoken", tokenHeaders[0], "Expected Token header to be 'testtoken', not '%v'", tokenHeaders[0]) - - assert.Equalf(t, "id=testidstring", r.URL.RawQuery, "Expected URL querystring to be id=testidstring, not %v", r.URL) - - decoder := json.NewDecoder(r.Body) - var req HTTPRequest - err := decoder.Decode(&req) - if err != nil { - assert.Failf(t, "Failed to decode message body", "Failed to decode message body: %v", err.Error()) - http.Error(w, err.Error(), http.StatusBadRequest) - return + + for i, testSet := range notifyHTTPModuleTests { + fmt.Printf("Running test %v - %v\n", i, testSet) + + // handler that validates that we get the right values + requestHandler := func(w http.ResponseWriter, r *http.Request) { + // Must get an appropriate Content-Type header + headerContentType, ok := r.Header["Content-Type"] + assert.True(t, ok, "Expected to receive Content-Type header") + assert.Len(t, headerContentType, 1, "Expected to receive exactly one Content-Type header") + assert.Equalf(t, "application/json", headerContentType[0], "Expected Content-Type header to be 'application/json', not '%v'", headerContentType[0]) + + tokenHeaders, ok := r.Header["Token"] + assert.True(t, ok, "Expected to receive Token header") + assert.Equalf(t, "testtoken", tokenHeaders[0], "Expected Token header to be 'testtoken', not '%v'", tokenHeaders[0]) + + host := r.Host + if testSet.ChangeHost { + assert.Equalf(t, "newhost", host, "Expected host to be 'newhost', not '%v'", host) + } else { + assert.True(t, strings.Contains(r.Host, "127.0.0.1"), "Expected host to be localhost") + } + + assert.Equalf(t, "id=testidstring", r.URL.RawQuery, "Expected URL querystring to be id=testidstring, not %v", r.URL) + + decoder := json.NewDecoder(r.Body) + var req HTTPRequest + err := decoder.Decode(&req) + if err != nil { + assert.Failf(t, "Failed to decode message body", "Failed to decode message body: %v", err.Error()) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + assert.Equalf(t, "template_open", req.Template, "Expected Template to be template_open, not %v", req.Template) + assert.Equalf(t, "testidstring", req.ID, "Expected ID to be testidstring, not %v", req.ID) + assert.Equalf(t, "testcluster", req.Cluster, "Expected Cluster to be testcluster, not %v", req.Cluster) + assert.Equalf(t, "testgroup", req.Group, "Expected Group to be testgroup, not %v", req.Group) + + fmt.Fprint(w, "ok") } - assert.Equalf(t, "template_open", req.Template, "Expected Template to be template_open, not %v", req.Template) - assert.Equalf(t, "testidstring", req.ID, "Expected ID to be testidstring, not %v", req.ID) - assert.Equalf(t, "testcluster", req.Cluster, "Expected Cluster to be testcluster, not %v", req.Cluster) - assert.Equalf(t, "testgroup", req.Group, "Expected Group to be testgroup, not %v", req.Group) + // create test server with handler + ts := httptest.NewServer(http.HandlerFunc(requestHandler)) + defer ts.Close() - fmt.Fprint(w, "ok") - } + module := fixtureHTTPNotifier() + viper.Set("notifier.test.url-open", fmt.Sprintf("%s?id={{.ID}}", ts.URL)) - // create test server with handler - ts := httptest.NewServer(http.HandlerFunc(requestHandler)) - defer ts.Close() + if testSet.ChangeHost { + viper.Set("notifier.test.headers", map[string]string{"Token": "testtoken", "Host": "newhost"}) + } - module := fixtureHTTPNotifier() - viper.Set("notifier.test.url-open", fmt.Sprintf("%s?id={{.ID}}", ts.URL)) + // Template sends the ID, cluster, and group + module.templateOpen, _ = template.New("test").Parse("{\"template\":\"template_open\",\"id\":\"{{.ID}}\",\"cluster\":\"{{.Cluster}}\",\"group\":\"{{.Group}}\"}") - // Template sends the ID, cluster, and group - module.templateOpen, _ = template.New("test").Parse("{\"template\":\"template_open\",\"id\":\"{{.ID}}\",\"cluster\":\"{{.Cluster}}\",\"group\":\"{{.Group}}\"}") + module.Configure("test", "notifier.test") - module.Configure("test", "notifier.test") + status := &protocol.ConsumerGroupStatus{ + Status: protocol.StatusWarning, + Cluster: "testcluster", + Group: "testgroup", + } - status := &protocol.ConsumerGroupStatus{ - Status: protocol.StatusWarning, - Cluster: "testcluster", - Group: "testgroup", + module.Notify(status, "testidstring", time.Now(), false) } - - module.Notify(status, "testidstring", time.Now(), false) } func TestHttpNotifier_Notify_Close(t *testing.T) { - // handler that validates that we get the right values - requestHandler := func(w http.ResponseWriter, r *http.Request) { - // Must get an appropriate Content-Type header - headers, ok := r.Header["Content-Type"] - assert.True(t, ok, "Expected to receive Content-Type header") - assert.Len(t, headers, 1, "Expected to receive exactly one Content-Type header") - assert.Equalf(t, "application/json", headers[0], "Expected Content-Type header to be 'application/json', not '%v'", headers[0]) - - tokenHeaders, ok := r.Header["Token"] - assert.True(t, ok, "Expected to receive Token header") - assert.Equalf(t, "testtoken", tokenHeaders[0], "Expected Token header to be 'testtoken', not '%v'", tokenHeaders[0]) - - assert.Equalf(t, "id=testidstring", r.URL.RawQuery, "Expected URL querystring to be id=testidstring, not %v", r.URL) - - decoder := json.NewDecoder(r.Body) - var req HTTPRequest - err := decoder.Decode(&req) - if err != nil { - assert.Failf(t, "Failed to decode message body", "Failed to decode message body: %v", err.Error()) - http.Error(w, err.Error(), http.StatusBadRequest) - return + + for i, testSet := range notifyHTTPModuleTests { + + fmt.Printf("Running test %v - %v\n", i, testSet) + // handler that validates that we get the right values + requestHandler := func(w http.ResponseWriter, r *http.Request) { + // Must get an appropriate Content-Type header + headers, ok := r.Header["Content-Type"] + assert.True(t, ok, "Expected to receive Content-Type header") + assert.Len(t, headers, 1, "Expected to receive exactly one Content-Type header") + assert.Equalf(t, "application/json", headers[0], "Expected Content-Type header to be 'application/json', not '%v'", headers[0]) + + tokenHeaders, ok := r.Header["Token"] + assert.True(t, ok, "Expected to receive Token header") + assert.Equalf(t, "testtoken", tokenHeaders[0], "Expected Token header to be 'testtoken', not '%v'", tokenHeaders[0]) + + host := r.Host + if testSet.ChangeHost { + assert.Equalf(t, "newhost", host, "Expected host to be 'newhost', not '%v'", host) + } else { + assert.True(t, strings.Contains(r.Host, "127.0.0.1"), "Expected host to be localhost") + } + + assert.Equalf(t, "id=testidstring", r.URL.RawQuery, "Expected URL querystring to be id=testidstring, not %v", r.URL) + + decoder := json.NewDecoder(r.Body) + var req HTTPRequest + err := decoder.Decode(&req) + if err != nil { + assert.Failf(t, "Failed to decode message body", "Failed to decode message body: %v", err.Error()) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + assert.Equalf(t, "template_close", req.Template, "Expected Template to be template_close, not %v", req.Template) + assert.Equalf(t, "testidstring", req.ID, "Expected ID to be testidstring, not %v", req.ID) + assert.Equalf(t, "testcluster", req.Cluster, "Expected Cluster to be testcluster, not %v", req.Cluster) + assert.Equalf(t, "testgroup", req.Group, "Expected Group to be testgroup, not %v", req.Group) + + fmt.Fprint(w, "ok") } - assert.Equalf(t, "template_close", req.Template, "Expected Template to be template_close, not %v", req.Template) - assert.Equalf(t, "testidstring", req.ID, "Expected ID to be testidstring, not %v", req.ID) - assert.Equalf(t, "testcluster", req.Cluster, "Expected Cluster to be testcluster, not %v", req.Cluster) - assert.Equalf(t, "testgroup", req.Group, "Expected Group to be testgroup, not %v", req.Group) + // create test server with handler + ts := httptest.NewServer(http.HandlerFunc(requestHandler)) + defer ts.Close() - fmt.Fprint(w, "ok") - } + module := fixtureHTTPNotifier() + viper.Set("notifier.test.send-close", true) + viper.Set("notifier.test.url-close", fmt.Sprintf("%s?id={{.ID}}", ts.URL)) - // create test server with handler - ts := httptest.NewServer(http.HandlerFunc(requestHandler)) - defer ts.Close() + if testSet.ChangeHost { + viper.Set("notifier.test.headers", map[string]string{"Token": "testtoken", "Host": "newhost"}) + } - module := fixtureHTTPNotifier() - viper.Set("notifier.test.send-close", true) - viper.Set("notifier.test.url-close", fmt.Sprintf("%s?id={{.ID}}", ts.URL)) + // Template sends the ID, cluster, and group + module.templateClose, _ = template.New("test").Parse("{\"template\":\"template_close\",\"id\":\"{{.ID}}\",\"cluster\":\"{{.Cluster}}\",\"group\":\"{{.Group}}\"}") - // Template sends the ID, cluster, and group - module.templateClose, _ = template.New("test").Parse("{\"template\":\"template_close\",\"id\":\"{{.ID}}\",\"cluster\":\"{{.Cluster}}\",\"group\":\"{{.Group}}\"}") + module.Configure("test", "notifier.test") - module.Configure("test", "notifier.test") + status := &protocol.ConsumerGroupStatus{ + Status: protocol.StatusWarning, + Cluster: "testcluster", + Group: "testgroup", + } - status := &protocol.ConsumerGroupStatus{ - Status: protocol.StatusWarning, - Cluster: "testcluster", - Group: "testgroup", + module.Notify(status, "testidstring", time.Now(), true) } - - module.Notify(status, "testidstring", time.Now(), true) }