Skip to content

Commit

Permalink
Add fail_if_body_too_large http probe option
Browse files Browse the repository at this point in the history
This can be used in conjunction with `body_size_limit` when it is
expected that endpoints return a body larger than the specified limit,
e.g. streaming endpoints that potentially return infinite data.

Signed-off-by: Justin Kromlinger <[email protected]>
  • Loading branch information
hashworks committed Nov 1, 2024
1 parent 73cc86f commit 2d225ab
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 1 deletion.
3 changes: 3 additions & 0 deletions CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ modules:
# Probe fails if SSL is not present.
[ fail_if_not_ssl: <boolean> | default = false ]

# Probe fails if a defined body_size_limit is exceeded.
[ fail_if_body_too_large: <boolean> | default = true ]

# Probe fails if response body matches regex.
fail_if_body_matches_regexp:
[ - <regex>, ... ]
Expand Down
8 changes: 8 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ type HTTPProbe struct {
NoFollowRedirects *bool `yaml:"no_follow_redirects,omitempty"`
FailIfSSL bool `yaml:"fail_if_ssl,omitempty"`
FailIfNotSSL bool `yaml:"fail_if_not_ssl,omitempty"`
FailIfBodyTooLarge *bool `yaml:"fail_if_body_too_large,omitempty"`
Method string `yaml:"method,omitempty"`
Headers map[string]string `yaml:"headers,omitempty"`
FailIfBodyMatchesRegexp []Regexp `yaml:"fail_if_body_matches_regexp,omitempty"`
Expand Down Expand Up @@ -455,6 +456,13 @@ func (s *HeaderMatch) UnmarshalYAML(unmarshal func(interface{}) error) error {
return nil
}

func (h HTTPProbe) GetFailIfBodyTooLarge() bool {
if h.FailIfBodyTooLarge == nil {
return true
}
return *h.FailIfBodyTooLarge
}

// isCompressionAcceptEncodingValid validates the compression +
// Accept-Encoding combination.
//
Expand Down
2 changes: 1 addition & 1 deletion prober/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr

if !requestErrored {
_, err = io.Copy(io.Discard, byteCounter)
if err != nil {
if err != nil && (errors.Is(err, &http.MaxBytesError{}) || httpConfig.GetFailIfBodyTooLarge()) {
logger.Info("Failed to read HTTP response body", "err", err)
success = false
}
Expand Down
27 changes: 27 additions & 0 deletions prober/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"testing"
"time"

"github.com/alecthomas/units"
"github.com/andybalholm/brotli"
"github.com/prometheus/client_golang/prometheus"
pconfig "github.com/prometheus/common/config"
Expand Down Expand Up @@ -838,6 +839,32 @@ func TestFailIfNotSSL(t *testing.T) {
checkRegistryResults(expectedResults, mfs, t)
}

func TestFailIfBodySizeTooLarge(t *testing.T) {
bodySizeLimit := units.Base2Bytes(1)

ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
resp := bytes.Repeat([]byte{'A'}, int(bodySizeLimit)+1)

w.Header().Set("Content-Length", strconv.Itoa(len(resp)))
w.WriteHeader(http.StatusOK)
w.Write(resp)
}))
defer ts.Close()

for _, failIfBodyTooLarge := range []bool{true, false} {
registry := prometheus.NewRegistry()
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
result := ProbeHTTP(testCTX, ts.URL,
config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, BodySizeLimit: bodySizeLimit, FailIfBodyTooLarge: &failIfBodyTooLarge}}, registry, log.NewNopLogger())
if result && failIfBodyTooLarge {
t.Fatal("Fail if body size too large succeeded unexpectedly")
} else if !result && !failIfBodyTooLarge {
t.Fatal("Dont't fail if body too large failed unexpectedly")
}
}
}

type logRecorder struct {
msgs map[string]bool
next *slog.Logger
Expand Down

0 comments on commit 2d225ab

Please sign in to comment.