Skip to content

Commit 6a806f7

Browse files
authored
fix: rely on IsResponseBodyProcessable (#281)
1 parent 2c5742e commit 6a806f7

File tree

2 files changed

+62
-32
lines changed

2 files changed

+62
-32
lines changed

main_test.go

Lines changed: 58 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ func TestLifecycle(t *testing.T) {
352352
{
353353
name: "response body accepted",
354354
inlineRules: `
355-
SecRuleEngine On\nSecResponseBodyAccess On\nSecRule RESPONSE_BODY \"@contains pooh\" \"id:101,phase:4,t:lowercase,deny\"
355+
SecRuleEngine On\nSecResponseBodyAccess On\nSecResponseBodyMimeType text/plain\nSecRule RESPONSE_BODY \"@contains pooh\" \"id:101,phase:4,t:lowercase,deny\"
356356
`,
357357
requestHdrsAction: types.ActionContinue,
358358
requestBodyAction: types.ActionContinue,
@@ -385,7 +385,7 @@ func TestLifecycle(t *testing.T) {
385385
{
386386
name: "response body accepted, no response body access",
387387
inlineRules: `
388-
SecRuleEngine On\nSecResponseBodyAccess Off\nSecRule RESPONSE_BODY \"@contains hello\" \"id:101,phase:4,t:lowercase,deny\"
388+
SecRuleEngine On\nSecResponseBodyAccess Off\nSecResponseBodyMimeType text/plain\nSecRule RESPONSE_BODY \"@contains hello\" \"id:101,phase:4,t:lowercase,deny\"
389389
`,
390390
requestHdrsAction: types.ActionContinue,
391391
requestBodyAction: types.ActionContinue,
@@ -396,7 +396,7 @@ func TestLifecycle(t *testing.T) {
396396
{
397397
name: "response body accepted, payload above process partial",
398398
inlineRules: `
399-
SecRuleEngine On\nSecResponseBodyAccess On\nSecResponseBodyLimit 2\nSecResponseBodyLimitAction ProcessPartial\nSecRule RESPONSE_BODY \"@contains hello\" \"id:101,phase:4,t:lowercase,deny\"
399+
SecRuleEngine On\nSecResponseBodyAccess On\nSecResponseBodyLimit 2\nSecResponseBodyLimitAction ProcessPartial\nSecResponseBodyMimeType text/plain\nSecRule RESPONSE_BODY \"@contains hello\" \"id:101,phase:4,t:lowercase,deny\"
400400
`,
401401
requestHdrsAction: types.ActionContinue,
402402
requestBodyAction: types.ActionContinue,
@@ -407,7 +407,7 @@ func TestLifecycle(t *testing.T) {
407407
{
408408
name: "response body denied, above limits",
409409
inlineRules: `
410-
SecRuleEngine On\nSecResponseBodyAccess On\nSecResponseBodyLimit 2\nSecResponseBodyLimitAction Reject\nSecRule RESPONSE_BODY \"@contains hello\" \"id:101,phase:4,t:lowercase,deny\"
410+
SecRuleEngine On\nSecResponseBodyAccess On\nSecResponseBodyLimit 2\nSecResponseBodyLimitAction Reject\nSecResponseBodyMimeType text/plain\nSecRule RESPONSE_BODY \"@contains hello\" \"id:101,phase:4,t:lowercase,deny\"
411411
`,
412412
requestHdrsAction: types.ActionContinue,
413413
requestBodyAction: types.ActionContinue,
@@ -796,38 +796,66 @@ func TestPerAuthorityDirectives(t *testing.T) {
796796
}
797797

798798
func TestEmptyBody(t *testing.T) {
799-
vmTest(t, func(t *testing.T, vm types.VMContext) {
800-
opt := proxytest.
801-
NewEmulatorOption().
802-
WithVMContext(vm).
803-
WithPluginConfiguration([]byte(`{"directives_map": {"default": [ "SecRequestBodyAccess On", "SecResponseBodyAccess On" ]}, "default_directives": "default"}`))
804-
805-
host, reset := proxytest.NewHostEmulator(opt)
806-
defer reset()
799+
testCases := []struct {
800+
title string
801+
isRespBodyProcessable bool
802+
}{
803+
{
804+
title: "Response body processable",
805+
isRespBodyProcessable: true,
806+
},
807+
{
808+
title: "Response body NOT processable",
809+
isRespBodyProcessable: false,
810+
},
811+
}
807812

808-
require.Equal(t, types.OnPluginStartStatusOK, host.StartPlugin())
813+
for _, tc := range testCases {
814+
t.Run(tc.title, func(t *testing.T) {
815+
vmTest(t, func(t *testing.T, vm types.VMContext) {
816+
opt := proxytest.
817+
NewEmulatorOption().
818+
WithVMContext(vm).
819+
WithPluginConfiguration([]byte(`{"directives_map": {"default": [ "SecRequestBodyAccess On", "SecResponseBodyAccess On", "SecResponseBodyMimeType text/plain"]}, "default_directives": "default"}`))
809820

810-
id := host.InitializeHttpContext()
821+
host, reset := proxytest.NewHostEmulator(opt)
822+
defer reset()
811823

812-
host.CallOnRequestHeaders(id, [][2]string{
813-
{":path", "/hello"},
814-
{":method", "GET"},
815-
{":authority", "localhost"},
816-
}, false)
824+
require.Equal(t, types.OnPluginStartStatusOK, host.StartPlugin())
817825

818-
action := host.CallOnRequestBody(id, []byte{}, false)
819-
require.Equal(t, types.ActionPause, action)
820-
action = host.CallOnRequestBody(id, []byte{}, true)
821-
require.Equal(t, types.ActionContinue, action)
826+
id := host.InitializeHttpContext()
827+
host.CallOnRequestHeaders(id, [][2]string{
828+
{":path", "/hello"},
829+
{":method", "GET"},
830+
{":authority", "localhost"},
831+
}, false)
832+
action := host.CallOnRequestBody(id, []byte{}, false)
833+
require.Equal(t, types.ActionPause, action)
834+
action = host.CallOnRequestBody(id, []byte{}, true)
835+
require.Equal(t, types.ActionContinue, action)
822836

823-
action = host.CallOnResponseBody(id, []byte{}, false)
824-
require.Equal(t, types.ActionPause, action)
825-
action = host.CallOnResponseBody(id, []byte{}, true)
826-
require.Equal(t, types.ActionContinue, action)
837+
if tc.isRespBodyProcessable {
838+
host.CallOnResponseHeaders(id, [][2]string{
839+
{":status", "200"},
840+
{"content-length", "0"},
841+
{"content-type", "text/plain"}}, false)
827842

828-
logs := strings.Join(host.GetCriticalLogs(), "\n")
829-
require.Empty(t, logs)
830-
})
843+
action = host.CallOnResponseBody(id, []byte{}, false)
844+
require.Equal(t, types.ActionPause, action)
845+
action = host.CallOnResponseBody(id, []byte{}, true)
846+
require.Equal(t, types.ActionContinue, action)
847+
} else {
848+
// If the ResponseBodyMimeType is not matched, we should just continue and not store the body
849+
action = host.CallOnResponseBody(id, []byte{}, false)
850+
require.Equal(t, types.ActionContinue, action)
851+
action = host.CallOnResponseBody(id, []byte{}, true)
852+
require.Equal(t, types.ActionContinue, action)
853+
}
854+
logs := strings.Join(host.GetCriticalLogs(), "\n")
855+
require.Empty(t, logs)
856+
})
857+
})
858+
}
831859
}
832860

833861
func TestLogError(t *testing.T) {

wasmplugin/plugin.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -559,8 +559,10 @@ func (ctx *httpContext) OnHttpResponseBody(bodySize int, endOfStream bool) types
559559
}
560560

561561
// Do not perform any action related to response body data if SecResponseBodyAccess is set to false
562-
if !tx.IsResponseBodyAccessible() {
563-
ctx.logger.Debug().Msg("Skipping response body inspection, SecResponseBodyAccess is off.")
562+
if !tx.IsResponseBodyAccessible() || !tx.IsResponseBodyProcessable() {
563+
ctx.logger.Debug().Bool("SecResponseBodyAccess", tx.IsResponseBodyAccessible()).
564+
Bool("IsResponseBodyProcessable", tx.IsResponseBodyProcessable()).
565+
Msg("Skipping response body inspection")
564566
// ProcessResponseBody is performed for phase 4 rules, checking already populated variables
565567
if !ctx.processedResponseBody {
566568
interruption, err := tx.ProcessResponseBody()

0 commit comments

Comments
 (0)