Skip to content

Commit 2d225ab

Browse files
committed
Add fail_if_body_too_large http probe option
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]>
1 parent 73cc86f commit 2d225ab

File tree

4 files changed

+39
-1
lines changed

4 files changed

+39
-1
lines changed

CONFIGURATION.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ modules:
8989
# Probe fails if SSL is not present.
9090
[ fail_if_not_ssl: <boolean> | default = false ]
9191

92+
# Probe fails if a defined body_size_limit is exceeded.
93+
[ fail_if_body_too_large: <boolean> | default = true ]
94+
9295
# Probe fails if response body matches regex.
9396
fail_if_body_matches_regexp:
9497
[ - <regex>, ... ]

config/config.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ type HTTPProbe struct {
211211
NoFollowRedirects *bool `yaml:"no_follow_redirects,omitempty"`
212212
FailIfSSL bool `yaml:"fail_if_ssl,omitempty"`
213213
FailIfNotSSL bool `yaml:"fail_if_not_ssl,omitempty"`
214+
FailIfBodyTooLarge *bool `yaml:"fail_if_body_too_large,omitempty"`
214215
Method string `yaml:"method,omitempty"`
215216
Headers map[string]string `yaml:"headers,omitempty"`
216217
FailIfBodyMatchesRegexp []Regexp `yaml:"fail_if_body_matches_regexp,omitempty"`
@@ -455,6 +456,13 @@ func (s *HeaderMatch) UnmarshalYAML(unmarshal func(interface{}) error) error {
455456
return nil
456457
}
457458

459+
func (h HTTPProbe) GetFailIfBodyTooLarge() bool {
460+
if h.FailIfBodyTooLarge == nil {
461+
return true
462+
}
463+
return *h.FailIfBodyTooLarge
464+
}
465+
458466
// isCompressionAcceptEncodingValid validates the compression +
459467
// Accept-Encoding combination.
460468
//

prober/http.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr
549549

550550
if !requestErrored {
551551
_, err = io.Copy(io.Discard, byteCounter)
552-
if err != nil {
552+
if err != nil && (errors.Is(err, &http.MaxBytesError{}) || httpConfig.GetFailIfBodyTooLarge()) {
553553
logger.Info("Failed to read HTTP response body", "err", err)
554554
success = false
555555
}

prober/http_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"testing"
3636
"time"
3737

38+
"github.com/alecthomas/units"
3839
"github.com/andybalholm/brotli"
3940
"github.com/prometheus/client_golang/prometheus"
4041
pconfig "github.com/prometheus/common/config"
@@ -838,6 +839,32 @@ func TestFailIfNotSSL(t *testing.T) {
838839
checkRegistryResults(expectedResults, mfs, t)
839840
}
840841

842+
func TestFailIfBodySizeTooLarge(t *testing.T) {
843+
bodySizeLimit := units.Base2Bytes(1)
844+
845+
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
846+
resp := bytes.Repeat([]byte{'A'}, int(bodySizeLimit)+1)
847+
848+
w.Header().Set("Content-Length", strconv.Itoa(len(resp)))
849+
w.WriteHeader(http.StatusOK)
850+
w.Write(resp)
851+
}))
852+
defer ts.Close()
853+
854+
for _, failIfBodyTooLarge := range []bool{true, false} {
855+
registry := prometheus.NewRegistry()
856+
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
857+
defer cancel()
858+
result := ProbeHTTP(testCTX, ts.URL,
859+
config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, BodySizeLimit: bodySizeLimit, FailIfBodyTooLarge: &failIfBodyTooLarge}}, registry, log.NewNopLogger())
860+
if result && failIfBodyTooLarge {
861+
t.Fatal("Fail if body size too large succeeded unexpectedly")
862+
} else if !result && !failIfBodyTooLarge {
863+
t.Fatal("Dont't fail if body too large failed unexpectedly")
864+
}
865+
}
866+
}
867+
841868
type logRecorder struct {
842869
msgs map[string]bool
843870
next *slog.Logger

0 commit comments

Comments
 (0)