Repository: corazawaf/coraza
Pull request #503 (2022-11-09 14:31:56)

Flatters WAF config API for better flexibility in setting memory limits and enabling BodyAccess
Following https://github.com/corazawaf/coraza/pull/499, I'm working on avoiding body-related actions when the bodies themself are not accessible (see https://github.com/corazawaf/coraza-proxy-wasm/pull/76). I'm facing a problem with `WithRequestBodyAccess` because it always enforces the body access, not taking into account any related user directive. 
This PR proposes to remove the enforcement. `WithRequestBodyAccess` and `WithResponseBodyAccess` would become a way to set memory limits, demanding to the traditional directives (`SecRequestBodyAccess` and `SecResponseBodyAccess`) the decision of enabling or not the body access.

I see value in slitting the enforcement from the configuration also considering actions like `ctl:requestBodyAccess`: for specific transactions the body could become accessible and would be okay to already have customized configurations in place if it happens.

Thanks for the feedback and alternative ideas/proposals!

P.S: `WithRequestBodyAccess` and `WithResponseBodyAccess` names would become not completely consistent, should I change them into something like `WithRequestBodyConfig` even if it will break implementations? 

anuraaga: Sorry for the late review. We want all the settings to be programmatically configurable without any text directives so don't think we can lose that ability for body access.

I think we could add an `Enabled` method to the body configs, or just flatten them instead of having separate sub-structs. Leaning towards latter, what do you think?
codecov-commenter: # [Codecov](https://codecov.io/gh/corazawaf/coraza/pull/503?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corazawaf) Report
Base: **77.83**% // Head: **77.83**% // Increases project coverage by **`+0.00%`** :tada:
> Coverage data is based on head [(`0494ee2`)](https://codecov.io/gh/corazawaf/coraza/pull/503?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corazawaf) compared to base [(`22f2f33`)](https://codecov.io/gh/corazawaf/coraza/commit/22f2f33e5863e7b633f071cdd0381b8db72961d0?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corazawaf).
> Patch coverage: 8.33% of modified lines in pull request are covered.

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##           v3/dev     #503   +/-   ##
=======================================
  Coverage   77.83%   77.83%           
=======================================
  Files         145      145           
  Lines        6830     6822    -8     
=======================================
- Hits         5316     5310    -6     
+ Misses       1276     1270    -6     
- Partials      238      242    +4     
```

| Flag | Coverage Δ | |
|---|---|---|
| default | `72.77% <8.33%> (-0.01%)` | :arrow_down: |
| examples | `27.05% <0.00%> (+0.03%)` | :arrow_up: |
| ftw | `55.64% <0.00%> (+0.06%)` | :arrow_up: |
| tinygo | `71.37% <8.33%> (-0.01%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corazawaf#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/corazawaf/coraza/pull/503?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corazawaf) | Coverage Δ | |
|---|---|---|
| [waf.go](https://codecov.io/gh/corazawaf/coraza/pull/503/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corazawaf#diff-d2FmLmdv) | `35.38% <0.00%> (-10.38%)` | :arrow_down: |
| [config.go](https://codecov.io/gh/corazawaf/coraza/pull/503/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corazawaf#diff-Y29uZmlnLmdv) | `39.50% <16.66%> (+3.71%)` | :arrow_up: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corazawaf). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corazawaf)

</details>

[:umbrella: View full report at Codecov](https://codecov.io/gh/corazawaf/coraza/pull/503?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corazawaf).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=corazawaf).

M4tteoP: Thanks @anuraaga! I removed both `RequestBodyConfig` and `ResponseBodyConfig` structures and refactored the API making each element individually configurable. PTAL 🙏
anuraaga: Thanks! Mostly LGTM
M4tteoP: Sorry for the delay! Addressed the review and updated the title to a more coherent one with the PR evolution
M4tteoP: Could you please take another look at this one? @jptosso @fzipi
Thanks! 🙏
M4tteoP: 1. Internally these limits are defined as `int64`. I can't see a reason for negative sizes, but to avoid conversions we may stick with int64 also for the exported function. I went for this solution in the last pushed commit.
Otherwise, we can swap everything to unsigned, even if I feel that `int64` is already enough in terms of super big files.
2. Done! Added "Bytes" for all the exported function names. 
jcchavezs: Another consideration here is that we access to those content types that
are being inspected and only buffer when inspection.

On Mon, 21 Nov 2022, 18:22 Matteo Pace, ***@***.***> wrote:

>
>    1. Internally these limits are defined as int64. I can't see a reason
>    for negative sizes, but to avoid conversions we may stick with int64 also
>    for the exported function. I went for this solution in the last pushed
>    commit.
>    Otherwise, we can swap everything to unsigned, even if I feel that
>    int64 is already enough in terms of super big files.
>    2. Done! Added "Bytes" for all the exported function names.
>
> —
> Reply to this email directly, view it on GitHub
> <https://github.com/corazawaf/coraza/pull/503#issuecomment-1322405515>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AAXOYAR3M64YSCGIY6ZCMUDWJOVUNANCNFSM6AAAAAAR3P365A>
> .
> You are receiving this because your review was requested.Message ID:
> ***@***.***>
>

fzipi: So, in summary:
- people here don't care about big sizes, because "most of the times you don't need them".
- we don't mind about negative numbers
- we just care most of all about simplicity and usage. People use `int`, and despite being good or bad, is what people use so we stick to that to avoid conversion.

Can we document these decisions somewhere else where they can be reached by more people? Also, for future Coraza developers :)
M4tteoP: Moved from `int64` to `int` and tried to properly comment about it. @fzipi PTAL 🙏
fzipi: In general looks good. But... are we considering the practical implications of an integer overflow [here](https://github.com/M4tteoP/coraza/blob/not_enforce_body_access/internal/corazawaf/body_buffer.go#L34-L60)?
Can we generate an overflow here: `l := len(data) + br.length`? If data is near max int, and br.length adds enought to 
M4tteoP: @fzipi that's a legit concern. I feel that the fundamental question is: are 32-bit machines a thing? If so, I think we could explicitly use int64 internally and just keep the `int` exposed to the API. The agreed limits will still be in place, but internally no problems like this one should happen anymore. @jptosso 
fzipi: What I want to point is that _assumptions_ are the "enemy" of security, in general. We make things explicit so we are _sure_. Making this explicit is about:
- documenting it properly and clearly.
- the limit is clearly checked. For a signed int, this implies checking that the file is between 0 and max int. We should explicitly take action if the size is negative (but not -1, because we are overriding that with `Unset`)

Hopefully, it is clear now.
fzipi: Can we fix conflicts here @M4tteoP? Thx!

Patch:
diff --git a/config.go b/config.go
index 628a9d1..a6db68d 100644
--- a/config.go
+++ b/config.go
@@ -30,11 +30,36 @@ type WAFConfig interface {
 	// WithContentInjection enables content injection.
 	WithContentInjection() WAFConfig
 
-	// WithRequestBodyAccess configures access to the request body.
-	WithRequestBodyAccess(config RequestBodyConfig) WAFConfig
-
-	// WithResponseBodyAccess configures access to the response body.
-	WithResponseBodyAccess(config ResponseBodyConfig) WAFConfig
+	// WithRequestBodyAccess enables access to the request body.
+	WithRequestBodyAccess() WAFConfig
+
+	// WithRequestBodyLimit sets the maximum number of bytes that can be read from the request body. Bytes beyond that set
+	// in WithInMemoryLimit will be buffered to disk.
+	// For usability purposes body limits are enforced as int (and not int64)
+	// int is a signed integer type that is at least 32 bits in size (platform-dependent size).
+	// While, the theoretical settable upper limit for 32-bit machines is 2GiB,
+	// it is recommended to keep this value as low as possible.
+	WithRequestBodyLimit(limit int) WAFConfig
+
+	// WithRequestBodyInMemoryLimit sets the maximum number of bytes that can be read from the request body and buffered in memory.
+	// For usability purposes body limits are enforced as int (and not int64)
+	// int is a signed integer type that is at least 32 bits in size (platform-dependent size).
+	// While, the theoretical settable upper limit for 32-bit machines is 2GiB,
+	// it is recommended to keep this value as low as possible.
+	WithRequestBodyInMemoryLimit(limit int) WAFConfig
+
+	// WithResponseBodyAccess enables access to the response body.
+	WithResponseBodyAccess() WAFConfig
+
+	// WithResponseBodyLimit sets the maximum number of bytes that can be read from the response body and buffered in memory.
+	// For usability purposes body limits are enforced as int (and not int64)
+	// int is a signed integer type that is at least 32 bits in size (platform-dependent size).
+	// While, the theoretical settable upper limit for 32-bit machines is 2GiB,
+	// it is recommended to keep this value as low as possible.
+	WithResponseBodyLimit(limit int) WAFConfig
+
+	// WithResponseBodyMimeTypes sets the mime types of responses that will be processed.
+	WithResponseBodyMimeTypes(mimeTypes []string) WAFConfig
 
 	// WithDebugLogger configures a debug logger.
 	WithDebugLogger(logger loggers.DebugLogger) WAFConfig
@@ -48,43 +73,15 @@ type WAFConfig interface {
 	WithRootFS(fs fs.FS) WAFConfig
 }
 
+const unsetLimit = -1
+
 // NewWAFConfig creates a new WAFConfig with the default settings.
 func NewWAFConfig() WAFConfig {
-	return &wafConfig{}
-}
-
-// RequestBodyConfig controls access to the request body.
-type RequestBodyConfig interface {
-	// WithLimit sets the maximum number of bytes that can be read from the request body.
-	// A request body going beyond WithInMemoryLimit will result in being buffered to disk.
-	WithLimit(limit int) RequestBodyConfig
-
-	// WithInMemoryLimit sets the maximum number of bytes that can be read from the request body and buffered in memory.
-	WithInMemoryLimit(limit int) RequestBodyConfig
-}
-
-// NewRequestBodyConfig returns a new RequestBodyConfig with the default settings.
-func NewRequestBodyConfig() RequestBodyConfig {
-	return &requestBodyConfig{}
-}
-
-// ResponseBodyConfig controls access to the response body.
-type ResponseBodyConfig interface {
-	// WithLimit sets the maximum number of bytes that can be read from the response body and buffered in memory.
-	// Keep in mind your machine architecture and memory/swap limits while setting it.
-	// E.g. 32-bit machine tested limit: 1073741824 (1GiB)
-	WithLimit(limit int) ResponseBodyConfig
-
-	// WithInMemoryLimit is not implemented for ResponseBody. The body will be just buffered in memory,
-	// therefore WithLimit already sets the in memory threshold
-
-	// WithMimeTypes sets the mime types of responses that will be processed.
-	WithMimeTypes(mimeTypes []string) ResponseBodyConfig
-}
-
-// NewResponseBodyConfig returns a new ResponseBodyConfig with the default settings.
-func NewResponseBodyConfig() ResponseBodyConfig {
-	return &responseBodyConfig{}
+	return &wafConfig{
+		requestBodyLimit:         unsetLimit,
+		requestBodyInMemoryLimit: unsetLimit,
+		responseBodyLimit:        unsetLimit,
+	}
 }
 
 // AuditLogConfig controls audit logging.
@@ -110,15 +107,22 @@ type wafRule struct {
 	file string
 }
 
+// For usability purposes body limits are enforced as int (and not int64)
+// int is a signed integer type that is at least 32 bits in size (platform-dependent size).
+// We still basically assume 64-bit usage where int are big sizes.
 type wafConfig struct {
-	rules            []wafRule
-	auditLog         *auditLogConfig
-	contentInjection bool
-	requestBody      *requestBodyConfig
-	responseBody     *responseBodyConfig
-	debugLogger      loggers.DebugLogger
-	errorCallback    func(rule types.MatchedRule)
-	fsRoot           fs.FS
+	rules                    []wafRule
+	auditLog                 *auditLogConfig
+	contentInjection         bool
+	requestBodyAccess        bool
+	requestBodyLimit         int
+	requestBodyInMemoryLimit int
+	responseBodyAccess       bool
+	responseBodyLimit        int
+	responseBodyMimeTypes    []string
+	debugLogger              loggers.DebugLogger
+	errorCallback            func(rule types.MatchedRule)
+	fsRoot                   fs.FS
 }
 
 func (c *wafConfig) WithRules(rules ...*corazawaf.Rule) WAFConfig {
@@ -157,15 +161,15 @@ func (c *wafConfig) WithContentInjection() WAFConfig {
 	return ret
 }
 
-func (c *wafConfig) WithRequestBodyAccess(config RequestBodyConfig) WAFConfig {
+func (c *wafConfig) WithRequestBodyAccess() WAFConfig {
 	ret := c.clone()
-	ret.requestBody = config.(*requestBodyConfig)
+	ret.requestBodyAccess = true
 	return ret
 }
 
-func (c *wafConfig) WithResponseBodyAccess(config ResponseBodyConfig) WAFConfig {
+func (c *wafConfig) WithResponseBodyAccess() WAFConfig {
 	ret := c.clone()
-	ret.responseBody = config.(*responseBodyConfig)
+	ret.responseBodyAccess = true
 	return ret
 }
 
@@ -195,59 +199,30 @@ func (c *wafConfig) clone() *wafConfig {
 	return &ret
 }
 
-type requestBodyConfig struct {
-	limit         int
-	inMemoryLimit int
-}
-
-var _ RequestBodyConfig = (*requestBodyConfig)(nil)
-
-func (c *requestBodyConfig) WithLimit(limit int) RequestBodyConfig {
+func (c *wafConfig) WithRequestBodyLimit(limit int) WAFConfig {
 	ret := c.clone()
-	ret.limit = limit
+	ret.requestBodyLimit = limit
 	return ret
 }
 
-func (c *requestBodyConfig) WithInMemoryLimit(limit int) RequestBodyConfig {
+func (c *wafConfig) WithRequestBodyInMemoryLimit(limit int) WAFConfig {
 	ret := c.clone()
-	ret.inMemoryLimit = limit
+	ret.requestBodyInMemoryLimit = limit
 	return ret
 }
 
-func (c *requestBodyConfig) clone() *requestBodyConfig {
-	ret := *c // copy
-	return &ret
-}
-
-type responseBodyConfig struct {
-	limit         int
-	inMemoryLimit int
-	mimeTypes     []string
-}
-
-func (c *responseBodyConfig) WithLimit(limit int) ResponseBodyConfig {
+func (c *wafConfig) WithResponseBodyLimit(limit int) WAFConfig {
 	ret := c.clone()
-	ret.limit = limit
+	ret.responseBodyLimit = limit
 	return ret
 }
 
-func (c *responseBodyConfig) WithInMemoryLimit(limit int) ResponseBodyConfig {
+func (c *wafConfig) WithResponseBodyMimeTypes(mimeTypes []string) WAFConfig {
 	ret := c.clone()
-	ret.inMemoryLimit = limit
+	ret.responseBodyMimeTypes = mimeTypes
 	return ret
 }
 
-func (c *responseBodyConfig) WithMimeTypes(mimeTypes []string) ResponseBodyConfig {
-	ret := c.clone()
-	ret.mimeTypes = mimeTypes
-	return ret
-}
-
-func (c *responseBodyConfig) clone() *responseBodyConfig {
-	ret := *c // copy
-	return &ret
-}
-
 type auditLogConfig struct {
 	relevantOnly bool
 	parts        types.AuditLogParts
diff --git a/internal/corazawaf/body_buffer.go b/internal/corazawaf/body_buffer.go
index 53781b7..1a09c48 100644
--- a/internal/corazawaf/body_buffer.go
+++ b/internal/corazawaf/body_buffer.go
@@ -64,7 +64,7 @@ func (br *BodyBuffer) Write(data []byte) (n int, err error) {
 	// bytes.Buffer growth is platform dependent with a growth rate capped at 2x. If the buffer can't grow it will panic with ErrTooLarge.
 	// See https://github.com/golang/go/blob/go1.19.4/src/bytes/buffer.go#L117 and https://go-review.googlesource.com/c/go/+/349994
 	// Local tests show these buffer limits:
-	// 32-bit machine: 2147483647 (2^30, 1GiB)
+	// 32-bit machine: 1073741824 (2^30, 1GiB)
 	// 64-bit machine: 34359738368 (2^35, 32GiB) (Not reached the ErrTooLarge panic, the OS triggered an OOM)
 	if targetLen > br.options.MemoryLimit {
 		if environment.IsTinyGo {
diff --git a/internal/corazawaf/waf.go b/internal/corazawaf/waf.go
index 9ce71a1..d6dd66d 100644
--- a/internal/corazawaf/waf.go
+++ b/internal/corazawaf/waf.go
@@ -100,6 +100,7 @@ type WAF struct {
 	// UploadDir is the directory where the uploaded files will be stored
 	UploadDir string
 
+	// Request body in memory limit excluding the size of any files being transported in the request.
 	RequestBodyNoFilesLimit int64
 
 	RequestBodyLimitAction types.BodyLimitAction
diff --git a/internal/seclang/directives.go b/internal/seclang/directives.go
index 6daa8fa..0ea5a16 100644
--- a/internal/seclang/directives.go
+++ b/internal/seclang/directives.go
@@ -100,9 +100,9 @@ func directiveSecResponseBodyAccess(options *DirectiveOptions) error {
 }
 
 func directiveSecRequestBodyLimit(options *DirectiveOptions) error {
-	limit, _ := strconv.ParseInt(options.Opts, 10, 64)
-	options.WAF.RequestBodyLimit = limit
-	return nil
+	var err error
+	options.WAF.RequestBodyLimit, err = strconv.ParseInt(options.Opts, 10, 64)
+	return err
 }
 
 func directiveSecRequestBodyAccess(options *DirectiveOptions) error {
@@ -200,8 +200,9 @@ func directiveSecRequestBodyLimitAction(options *DirectiveOptions) error {
 }
 
 func directiveSecRequestBodyInMemoryLimit(options *DirectiveOptions) error {
-	options.WAF.RequestBodyInMemoryLimit, _ = strconv.ParseInt(options.Opts, 10, 64)
-	return nil
+	var err error
+	options.WAF.RequestBodyInMemoryLimit, err = strconv.ParseInt(options.Opts, 10, 64)
+	return err
 }
 
 func directiveSecRemoteRulesFailAction(options *DirectiveOptions) error {
diff --git a/operators/pm.go b/operators/pm.go
index 33cecdb..898d665 100644
--- a/operators/pm.go
+++ b/operators/pm.go
@@ -13,9 +13,6 @@ import (
 	"github.com/corazawaf/coraza/v3/rules"
 )
 
-// TODO according to coraza researchs, re2 matching is faster than ahocorasick
-// maybe we should switch in the future
-// pm is always lowercase
 type pm struct {
 	matcher ahocorasick.AhoCorasick
 }
diff --git a/waf.go b/waf.go
index 2900c4f..60df7a7 100644
--- a/waf.go
+++ b/waf.go
@@ -77,25 +77,37 @@ func NewWAF(config WAFConfig) (WAF, error) {
 		waf.ContentInjection = true
 	}
 
-	if r := c.requestBody; r != nil {
-		if r.limit <= 0 {
+	if c.requestBodyAccess {
+		waf.RequestBodyAccess = true
+	}
+
+	if c.requestBodyLimit != unsetLimit {
+		if c.requestBodyLimit <= 0 {
 			return nil, errors.New("request body limit should be bigger than 0")
 		}
 
-		if r.limit < r.inMemoryLimit {
+		if c.requestBodyLimit < c.requestBodyInMemoryLimit {
 			return nil, errors.New("request body limit should be at least the memory limit")
 		}
-		waf.RequestBodyAccess = true
-		waf.RequestBodyLimit = int64(r.limit)
-		waf.RequestBodyInMemoryLimit = int64(r.inMemoryLimit)
+		waf.RequestBodyLimit = int64(c.requestBodyLimit)
 	}
 
-	if r := c.responseBody; r != nil {
-		if r.limit <= 0 {
-			return nil, errors.New("response body limit should be bigger than 0")
+	if c.requestBodyInMemoryLimit != unsetLimit {
+		if c.requestBodyInMemoryLimit <= 0 {
+			return nil, errors.New("request body memory limit should be bigger than 0")
 		}
+		waf.RequestBodyInMemoryLimit = int64(c.requestBodyInMemoryLimit)
+	}
+
+	if c.responseBodyAccess {
 		waf.ResponseBodyAccess = true
-		waf.ResponseBodyLimit = int64(r.limit)
+	}
+
+	if c.responseBodyLimit != unsetLimit {
+		if c.responseBodyLimit <= 0 {
+			return nil, errors.New("response body limit should be bigger than 0")
+		}
+		waf.ResponseBodyLimit = int64(c.responseBodyLimit)
 	}
 
 	if c.errorCallback != nil {


Test patch:
diff --git a/http/middleware_test.go b/http/middleware_test.go
index 6cec612..b8c88bd 100644
--- a/http/middleware_test.go
+++ b/http/middleware_test.go
@@ -301,7 +301,7 @@ func TestHttpServer(t *testing.T) {
 	SecRule RESPONSE_BODY "@contains password" "id:200, phase:4,deny, status:403,msg:'Invalid response body',log,auditlog"
 `).WithErrorCallback(errLogger(t)).WithDebugLogger(&debugLogger{t: t})
 			if l := tCase.reqBodyLimit; l > 0 {
-				conf = conf.WithRequestBodyAccess(coraza.NewRequestBodyConfig().WithLimit(l).WithInMemoryLimit(l))
+				conf = conf.WithRequestBodyAccess().WithRequestBodyLimit(l).WithRequestBodyInMemoryLimit(l)
 			}
 			waf, err := coraza.NewWAF(conf)
 			if err != nil {
diff --git a/testing/engine_test.go b/testing/engine_test.go
index 7a0876b..68eef74 100644
--- a/testing/engine_test.go
+++ b/testing/engine_test.go
@@ -71,9 +71,7 @@ func TestRequest(t *testing.T) {
 func TestResponse(t *testing.T) {
 	waf, err := coraza.NewWAF(
 		coraza.NewWAFConfig().
-			WithResponseBodyAccess(
-				coraza.NewResponseBodyConfig().WithLimit(21),
-			),
+			WithResponseBodyAccess().WithResponseBodyLimit(21),
 	)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err.Error())
diff --git a/waf_test.go b/waf_test.go
index 09cc9a5..d7e9d90 100644
--- a/waf_test.go
+++ b/waf_test.go
@@ -7,26 +7,32 @@ import "testing"
 
 func TestNewWAFLimits(t *testing.T) {
 	testCases := map[string]struct {
-		expectedErr string
-		cfg         requestBodyConfig
+		expectedErr   string
+		limit         int
+		inMemoryLimit int
 	}{
 		"empty limit": {
-			cfg:         requestBodyConfig{},
-			expectedErr: "request body limit should be bigger than 0",
+			expectedErr:   "request body limit should be bigger than 0",
+			limit:         0,
+			inMemoryLimit: 2,
+		},
+		"empty memory limit": {
+			expectedErr:   "request body memory limit should be bigger than 0",
+			limit:         2,
+			inMemoryLimit: 0,
 		},
 		"memory limit bigger than limit": {
-			cfg: requestBodyConfig{
-				limit:         5,
-				inMemoryLimit: 9,
-			},
-			expectedErr: "request body limit should be at least the memory limit",
+			limit:         5,
+			inMemoryLimit: 9,
+			expectedErr:   "request body limit should be at least the memory limit",
 		},
 	}
 
 	for name, tCase := range testCases {
 		t.Run(name, func(t *testing.T) {
 			_, err := NewWAF(&wafConfig{
-				requestBody: &tCase.cfg,
+				requestBodyLimit:         tCase.limit,
+				requestBodyInMemoryLimit: tCase.inMemoryLimit,
 			})
 
 			if tCase.expectedErr != "" {