diff --git a/plugins/inputs/http_response/README.md b/plugins/inputs/http_response/README.md index 02dbd45d6..d8d0e9920 100644 --- a/plugins/inputs/http_response/README.md +++ b/plugins/inputs/http_response/README.md @@ -54,6 +54,12 @@ to use them. # {'fake':'data'} # ''' + ## Optional HTTP Request Body Form + ## Key value pairs to encode and set at URL form. Can be used with the POST + ## method + application/x-www-form-urlencoded content type to replicate the + ## POSTFORM method. + # body_form = { "key": "value" } + ## Optional name of the field that will contain the body of the response. ## By default it is set to an empty String indicating that the body's ## content won't be added diff --git a/plugins/inputs/http_response/http_response.go b/plugins/inputs/http_response/http_response.go index 46e8fa48f..f47d884ac 100644 --- a/plugins/inputs/http_response/http_response.go +++ b/plugins/inputs/http_response/http_response.go @@ -38,6 +38,7 @@ type HTTPResponse struct { URLs []string `toml:"urls"` HTTPProxy string `toml:"http_proxy"` Body string + BodyForm map[string][]string `toml:"body_form"` Method string ResponseTimeout config.Duration HTTPHeaderTags map[string]string `toml:"http_header_tags"` @@ -193,7 +194,16 @@ func (h *HTTPResponse) httpGather(u string) (map[string]interface{}, map[string] var body io.Reader if h.Body != "" { body = strings.NewReader(h.Body) + } else if len(h.BodyForm) != 0 { + values := url.Values{} + for k, vs := range h.BodyForm { + for _, v := range vs { + values.Add(k, v) + } + } + body = strings.NewReader(values.Encode()) } + request, err := http.NewRequest(h.Method, u, body) if err != nil { return nil, nil, err diff --git a/plugins/inputs/http_response/http_response_test.go b/plugins/inputs/http_response/http_response_test.go index ebeee23d2..23cb420f9 100644 --- a/plugins/inputs/http_response/http_response_test.go +++ b/plugins/inputs/http_response/http_response_test.go @@ -98,6 +98,20 @@ func setUpTestMux() http.Handler { w.Header().Set("Content-Type", "application/json; charset=utf-8") fmt.Fprintf(w, "hit the good page!") }) + mux.HandleFunc("/form", func(w http.ResponseWriter, req *http.Request) { + body, err := io.ReadAll(req.Body) + defer req.Body.Close() + if err != nil { + http.Error(w, "couldn't read request body", http.StatusBadRequest) + return + } + if string(body) != "list=foobar&list=fizbuzz&test=42" { + fmt.Println(string(body)) + w.WriteHeader(http.StatusBadRequest) + } else { + w.WriteHeader(http.StatusOK) + } + }) mux.HandleFunc("/invalidUTF8", func(w http.ResponseWriter, req *http.Request) { w.Write([]byte{0xff, 0xfe, 0xfd}) //nolint:errcheck // ignore the returned error as the test will fail anyway }) @@ -314,6 +328,46 @@ func TestResponseBodyField(t *testing.T) { checkOutput(t, &acc, expectedFields, expectedTags, nil, nil) } +func TestResponseBodyFormField(t *testing.T) { + mux := setUpTestMux() + ts := httptest.NewServer(mux) + defer ts.Close() + + h := &HTTPResponse{ + Log: testutil.Logger{}, + URLs: []string{ts.URL + "/form"}, + BodyForm: map[string][]string{ + "test": {"42"}, + "list": {"foobar", "fizbuzz"}, + }, + Method: "POST", + Headers: map[string]string{ + "Content-Type": "application/x-www-form-urlencoded", + }, + ResponseTimeout: config.Duration(time.Second * 20), + ResponseBodyField: "my_body_field", + } + + var acc testutil.Accumulator + require.NoError(t, h.Gather(&acc)) + + expectedFields := map[string]interface{}{ + "http_response_code": http.StatusOK, + "result_type": "success", + "result_code": 0, + "response_time": nil, + "content_length": nil, + "my_body_field": "", + } + expectedTags := map[string]interface{}{ + "server": nil, + "method": "POST", + "status_code": "200", + "result": "success", + } + checkOutput(t, &acc, expectedFields, expectedTags, nil, nil) +} + func TestResponseBodyMaxSize(t *testing.T) { mux := setUpTestMux() ts := httptest.NewServer(mux) diff --git a/plugins/inputs/http_response/sample.conf b/plugins/inputs/http_response/sample.conf index d8d3652a2..34f1f6339 100644 --- a/plugins/inputs/http_response/sample.conf +++ b/plugins/inputs/http_response/sample.conf @@ -29,6 +29,12 @@ # {'fake':'data'} # ''' + ## Optional HTTP Request Body Form + ## Key value pairs to encode and set at URL form. Can be used with the POST + ## method + application/x-www-form-urlencoded content type to replicate the + ## POSTFORM method. + # body_form = { "key": "value" } + ## Optional name of the field that will contain the body of the response. ## By default it is set to an empty String indicating that the body's ## content won't be added