Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing the way the HTTP header Host is set #614

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion core/internal/notifier/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"net"
"net/http"
"regexp"
"strings"
"text/template"
"time"

Expand Down Expand Up @@ -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)
Expand Down
206 changes: 123 additions & 83 deletions core/internal/notifier/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"encoding/json"
"fmt"
"net/http"
"strings"
"text/template"
"time"

Expand Down Expand Up @@ -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)
}