Skip to content

Commit 7e6b21b

Browse files
committed
* Improved way how to configure this plugin
1 parent 02ef4f6 commit 7e6b21b

File tree

3 files changed

+135
-67
lines changed

3 files changed

+135
-67
lines changed

README.md

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,19 @@ Provides a directive to filter response bodies.
1414

1515
## Usage
1616

17-
Add ``filter rule`` blocks to your CaddyFile.
17+
Add ``filter`` block to your CaddyFile which contains one ore more ``rule`` blocks.
1818

1919
```
20-
filter rule {
21-
path <regexp pattern>
22-
content_type <regexp pattern>
23-
search_pattern <regexp pattern>
24-
replacement <replacement pattern>
20+
filter {
21+
rule {
22+
path <regexp pattern>
23+
content_type <regexp pattern>
24+
search_pattern <regexp pattern>
25+
replacement <replacement pattern>
26+
}
27+
rule ...
28+
maximumBufferSize <maximum buffer size in bytes>
2529
}
26-
file maximumBufferSize <maximum buffer size in bytes>
2730
```
2831

2932
> **Important:** Define ``path`` and/or ``content_type`` not to open. Slack rules could dramatically impact the system performance because every response is recorded to memory before returning it.
@@ -53,30 +56,36 @@ file maximumBufferSize <maximum buffer size in bytes>
5356
Replace in every text file ``Foo`` with ``Bar``.
5457

5558
```
56-
filter rule {
57-
path .*\.txt
58-
search_pattern "Foo"
59-
replacement "Bar"
59+
filter {
60+
rule {
61+
path .*\.txt
62+
search_pattern "Foo"
63+
replacement "Bar"
64+
}
6065
}
6166
```
6267

6368
Add Google Analytics to every HTML page.
6469

6570
```
66-
filter rule {
67-
path .*\.html
68-
search_pattern "</title>"
69-
replacement "</title><script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-12345678-9', 'auto');ga('send', 'pageview');</script>"
71+
filter {
72+
rule {
73+
path .*\.html
74+
search_pattern "</title>"
75+
replacement "</title><script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-12345678-9', 'auto');ga('send', 'pageview');</script>"
76+
}
7077
}
7178
```
7279

7380
Insert server name in every HTML page
7481

7582
```
76-
filter rule {
77-
content_type text/html.*
78-
search_pattern "Server"
79-
replacement "This site was provided by {response_header_Server}"
83+
filter {
84+
rule {
85+
content_type text/html.*
86+
search_pattern "Server"
87+
replacement "This site was provided by {response_header_Server}"
88+
}
8089
}
8190
```
8291

init.go

Lines changed: 54 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -35,34 +35,60 @@ func parseConfiguration(controller *caddy.Controller) (*filterHandler, error) {
3535
handler.maximumBufferSize = defaultMaxBufferSize
3636

3737
for controller.Next() {
38-
args := controller.RemainingArgs()
39-
if len(args) <= 0 {
40-
return nil, controller.Errf("No command provided.")
41-
}
42-
var err error
43-
switch args[0] {
44-
case "rule":
45-
err = evalRule(controller, args[1:], handler)
46-
case "maximumBufferSize":
47-
err = evalMaximumBufferSize(controller, args[1:], handler)
48-
default:
49-
err = controller.Errf("Unknown command '%v'.", args[0])
50-
}
38+
err := evalFilterBlock(controller, handler)
5139
if err != nil {
5240
return nil, err
5341
}
5442
}
43+
44+
if len(handler.rules) <= 0 {
45+
return nil, controller.Err("No rule block provided.")
46+
}
5547
return handler, nil
5648
}
5749

50+
func evalFilterBlock(controller *caddy.Controller, target *filterHandler) error {
51+
args := controller.RemainingArgs()
52+
if len(args) == 0 {
53+
return evalDefaultFilterBlock(controller, target)
54+
}
55+
return evalNamedBlock(controller, args, target)
56+
}
57+
58+
func evalDefaultFilterBlock(controller *caddy.Controller, target *filterHandler) error {
59+
for controller.NextBlock() {
60+
args := []string{controller.Val()}
61+
args = append(args, controller.RemainingArgs()...)
62+
63+
if controller.NextArg() && controller.Val() == "{" {
64+
controller.IncrNest()
65+
}
66+
err := evalNamedBlock(controller, args, target)
67+
if err != nil {
68+
return err
69+
}
70+
}
71+
return nil
72+
}
73+
74+
func evalNamedBlock(controller *caddy.Controller, args []string, target *filterHandler) error {
75+
switch args[0] {
76+
case "rule":
77+
return evalRule(controller, args[1:], target)
78+
case "maximumBufferSize":
79+
return evalMaximumBufferSize(controller, args[1:], target)
80+
}
81+
return controller.Errf("Unknown directive: %v", args[0])
82+
}
83+
5884
func evalRule(controller *caddy.Controller, args []string, target *filterHandler) (err error) {
5985
if len(args) > 0 {
60-
return controller.Errf("No more arguments for filter command 'rule' supported.")
86+
return controller.Errf("No more arguments for filter block 'rule' supported.")
6187
}
6288
targetRule := new(rule)
6389
for controller.NextBlock() {
64-
propertyName := controller.Val()
65-
switch propertyName {
90+
optionName := controller.Val()
91+
switch optionName {
6692
case "path":
6793
err = evalPath(controller, targetRule)
6894
case "content_type":
@@ -72,60 +98,60 @@ func evalRule(controller *caddy.Controller, args []string, target *filterHandler
7298
case "replacement":
7399
err = evalReplacement(controller, targetRule)
74100
default:
75-
err = controller.Errf("Unknown property name '%v'.", propertyName)
101+
err = controller.Errf("Unknown option: %v", optionName)
76102
}
77103
if err != nil {
78104
return err
79105
}
80106
}
81107
if targetRule.path == nil && targetRule.contentType == nil {
82-
return controller.Errf("Neither 'path' nor 'content_type' definition was provided for filter.")
108+
return controller.Errf("Neither 'path' nor 'content_type' definition was provided for filter rule block.")
83109
}
84110
if targetRule.searchPattern == nil {
85-
return controller.Errf("No 'search_pattern' definition was provided for filter.")
111+
return controller.Errf("No 'search_pattern' definition was provided for filter rule block.")
86112
}
87113
target.rules = append(target.rules, targetRule)
88114
return nil
89115
}
90116

91117
func evalPath(controller *caddy.Controller, target *rule) error {
92-
return evalRegexpProperty(controller, func(value *regexp.Regexp) error {
118+
return evalRegexpOption(controller, func(value *regexp.Regexp) error {
93119
target.path = value
94120
return nil
95121
})
96122
}
97123

98124
func evalContentType(controller *caddy.Controller, target *rule) error {
99-
return evalRegexpProperty(controller, func(value *regexp.Regexp) error {
125+
return evalRegexpOption(controller, func(value *regexp.Regexp) error {
100126
target.contentType = value
101127
return nil
102128
})
103129
}
104130

105131
func evalSearchPattern(controller *caddy.Controller, target *rule) error {
106-
return evalRegexpProperty(controller, func(value *regexp.Regexp) error {
132+
return evalRegexpOption(controller, func(value *regexp.Regexp) error {
107133
target.searchPattern = value
108134
return nil
109135
})
110136
}
111137

112138
func evalReplacement(controller *caddy.Controller, target *rule) error {
113-
return evalSimpleProperty(controller, func(value string) error {
139+
return evalSimpleOption(controller, func(value string) error {
114140
target.replacement = []byte(value)
115141
return nil
116142
})
117143
}
118144

119-
func evalSimpleProperty(controller *caddy.Controller, setter func(string) error) error {
145+
func evalSimpleOption(controller *caddy.Controller, setter func(string) error) error {
120146
args := controller.RemainingArgs()
121147
if len(args) != 1 {
122148
return controller.ArgErr()
123149
}
124150
return setter(args[0])
125151
}
126152

127-
func evalRegexpProperty(controller *caddy.Controller, setter func(*regexp.Regexp) error) error {
128-
return evalSimpleProperty(controller, func(plainValue string) error {
153+
func evalRegexpOption(controller *caddy.Controller, setter func(*regexp.Regexp) error) error {
154+
return evalSimpleOption(controller, func(plainValue string) error {
129155
value, err := regexp.Compile(plainValue)
130156
if err != nil {
131157
return err
@@ -136,11 +162,11 @@ func evalRegexpProperty(controller *caddy.Controller, setter func(*regexp.Regexp
136162

137163
func evalMaximumBufferSize(controller *caddy.Controller, args []string, target *filterHandler) (err error) {
138164
if len(args) != 1 {
139-
return controller.Errf("There are exact one argument for filter command 'maximumBufferSize' expected.")
165+
return controller.Errf("There are exact one argument for filter directive 'maximumBufferSize' expected.")
140166
}
141167
value, err := strconv.Atoi(args[0])
142168
if err != nil {
143-
return controller.Errf("There is no valid value for filter command 'maximumBufferSize' provided. Got: %v", err)
169+
return controller.Errf("There is no valid value for filter directive 'maximumBufferSize' provided. Got: %v", err)
144170
}
145171
target.maximumBufferSize = value
146172
return nil

init_test.go

Lines changed: 53 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
. "gopkg.in/check.v1"
88
"regexp"
99
"regexp/syntax"
10+
"fmt"
1011
)
1112

1213
type initTest struct{}
@@ -32,7 +33,45 @@ func (s *initTest) Test_setup(c *C) {
3233
c.Assert(string(r.replacement), Equals, "myReplacement")
3334
}
3435

35-
func (s *initTest) Test_parseConfiguration(c *C) {
36+
func (s *initTest) Test_parseConfiguration_default(c *C) {
37+
handler, err := parseConfiguration(s.newControllerFor("filter {\nrule {\npath myPath\ncontent_type myContentType\nsearch_pattern mySearchPattern\nreplacement myReplacement\n}\n}\n"))
38+
c.Assert(err, IsNil)
39+
c.Assert(len(handler.rules), Equals, 1)
40+
r := handler.rules[0]
41+
c.Assert(r.path.String(), Equals, "myPath")
42+
c.Assert(r.contentType.String(), Equals, "myContentType")
43+
c.Assert(r.searchPattern.String(), Equals, "mySearchPattern")
44+
c.Assert(string(r.replacement), Equals, "myReplacement")
45+
46+
fmt.Println()
47+
fmt.Println()
48+
fmt.Println()
49+
50+
handler, err = parseConfiguration(s.newControllerFor("filter {\n" +
51+
"rule {\npath myPath\nsearch_pattern mySearchPattern\n}\n" +
52+
"rule {\npath myPath2\nsearch_pattern mySearchPattern2\n}\n" +
53+
"maximumBufferSize 666\n" +
54+
"}",
55+
),
56+
)
57+
c.Assert(err, IsNil)
58+
c.Assert(len(handler.rules), Equals, 2)
59+
r = handler.rules[0]
60+
c.Assert(r.path.String(), Equals, "myPath")
61+
c.Assert(r.searchPattern.String(), Equals, "mySearchPattern")
62+
r = handler.rules[1]
63+
c.Assert(r.path.String(), Equals, "myPath2")
64+
c.Assert(r.searchPattern.String(), Equals, "mySearchPattern2")
65+
c.Assert(handler.maximumBufferSize, Equals, 666)
66+
67+
_, err = parseConfiguration(s.newControllerFor("filter moo"))
68+
c.Assert(err, DeepEquals, errors.New("Testfile:1 - Parse error: Unknown directive: moo"))
69+
70+
_, err = parseConfiguration(s.newControllerFor("filter"))
71+
c.Assert(err, DeepEquals, errors.New("Testfile:1 - Parse error: No rule block provided."))
72+
}
73+
74+
func (s *initTest) Test_parseConfiguration_directNamed(c *C) {
3675
handler, err := parseConfiguration(s.newControllerFor("filter rule {\npath myPath\ncontent_type myContentType\nsearch_pattern mySearchPattern\nreplacement myReplacement\n}\n"))
3776
c.Assert(err, IsNil)
3877
c.Assert(len(handler.rules), Equals, 1)
@@ -56,36 +95,30 @@ func (s *initTest) Test_parseConfiguration(c *C) {
5695
c.Assert(r.path.String(), Equals, "myPath2")
5796
c.Assert(r.searchPattern.String(), Equals, "mySearchPattern2")
5897
c.Assert(handler.maximumBufferSize, Equals, 666)
59-
60-
_, err = parseConfiguration(s.newControllerFor("filter moo"))
61-
c.Assert(err, DeepEquals, errors.New("Testfile:1 - Parse error: Unknown command 'moo'."))
62-
63-
_, err = parseConfiguration(s.newControllerFor("filter"))
64-
c.Assert(err, DeepEquals, errors.New("Testfile:1 - Parse error: No command provided."))
6598
}
6699

67-
func (s *initTest) Test_evalSimpleProperty(c *C) {
68-
err := evalSimpleProperty(s.newControllerFor("\"my value\""), func(value string) error {
100+
func (s *initTest) Test_evalSimpleOption(c *C) {
101+
err := evalSimpleOption(s.newControllerFor("\"my value\""), func(value string) error {
69102
c.Assert(value, Equals, "my value")
70103
return nil
71104
})
72105
c.Assert(err, IsNil)
73106

74-
err = evalSimpleProperty(s.newControllerFor(""), func(value string) error {
107+
err = evalSimpleOption(s.newControllerFor(""), func(value string) error {
75108
c.Error("This method should not be called.")
76109
return nil
77110
})
78111
c.Assert(err, DeepEquals, errors.New("Testfile:1 - Parse error: Wrong argument count or unexpected line ending after 'start'"))
79112
}
80113

81-
func (s *initTest) Test_evalRegexpProperty(c *C) {
82-
err := evalRegexpProperty(s.newControllerFor("f.*bar"), func(value *regexp.Regexp) error {
114+
func (s *initTest) Test_evalRegexpOption(c *C) {
115+
err := evalRegexpOption(s.newControllerFor("f.*bar"), func(value *regexp.Regexp) error {
83116
c.Assert(value.MatchString("foobar"), Equals, true)
84117
return nil
85118
})
86119
c.Assert(err, IsNil)
87120

88-
err = evalRegexpProperty(s.newControllerFor("<???"), func(value *regexp.Regexp) error {
121+
err = evalRegexpOption(s.newControllerFor("<???"), func(value *regexp.Regexp) error {
89122
c.Error("This method should not be called.")
90123
return nil
91124
})
@@ -132,16 +165,16 @@ func (s *initTest) Test_evalRule(c *C) {
132165
c.Assert(string(r.replacement), Equals, "myReplacement")
133166

134167
err = evalRule(s.newControllerFor("{\nfoo bar\n}\n"), []string{}, handler)
135-
c.Assert(err, DeepEquals, errors.New("Testfile:2 - Parse error: Unknown property name 'foo'."))
168+
c.Assert(err, DeepEquals, errors.New("Testfile:2 - Parse error: Unknown option: foo"))
136169

137170
err = evalRule(s.newControllerFor("{\n}\n"), []string{}, handler)
138-
c.Assert(err, DeepEquals, errors.New("Testfile:2 - Parse error: Neither 'path' nor 'content_type' definition was provided for filter."))
171+
c.Assert(err, DeepEquals, errors.New("Testfile:2 - Parse error: Neither 'path' nor 'content_type' definition was provided for filter rule block."))
139172

140173
err = evalRule(s.newControllerFor("{\npath myPath\n}\n"), []string{}, handler)
141-
c.Assert(err, DeepEquals, errors.New("Testfile:3 - Parse error: No 'search_pattern' definition was provided for filter."))
174+
c.Assert(err, DeepEquals, errors.New("Testfile:3 - Parse error: No 'search_pattern' definition was provided for filter rule block."))
142175

143176
err = evalRule(s.newControllerFor(""), []string{"foo"}, handler)
144-
c.Assert(err, DeepEquals, errors.New("Testfile:1 - Parse error: No more arguments for filter command 'rule' supported."))
177+
c.Assert(err, DeepEquals, errors.New("Testfile:1 - Parse error: No more arguments for filter block 'rule' supported."))
145178
}
146179

147180
func (s *initTest) Test_evalMaximumBufferSize(c *C) {
@@ -151,14 +184,14 @@ func (s *initTest) Test_evalMaximumBufferSize(c *C) {
151184
c.Assert(handler.maximumBufferSize, Equals, 123)
152185

153186
err = evalMaximumBufferSize(s.newControllerFor(""), []string{}, handler)
154-
c.Assert(err, DeepEquals, errors.New("Testfile:1 - Parse error: There are exact one argument for filter command 'maximumBufferSize' expected."))
187+
c.Assert(err, DeepEquals, errors.New("Testfile:1 - Parse error: There are exact one argument for filter directive 'maximumBufferSize' expected."))
155188

156189
err = evalMaximumBufferSize(s.newControllerFor(""), []string{"abc"}, handler)
157-
c.Assert(err, DeepEquals, errors.New("Testfile:1 - Parse error: There is no valid value for filter command 'maximumBufferSize' provided. Got: strconv.ParseInt: parsing \"abc\": invalid syntax"))
190+
c.Assert(err, DeepEquals, errors.New("Testfile:1 - Parse error: There is no valid value for filter directive 'maximumBufferSize' provided. Got: strconv.ParseInt: parsing \"abc\": invalid syntax"))
158191
}
159192

160193
func (s *initTest) newControllerFor(plainTokens string) *caddy.Controller {
161-
controller := caddy.NewTestController("http", "start "+plainTokens)
194+
controller := caddy.NewTestController("http", "start " + plainTokens)
162195
if !controller.Next() {
163196
panic("There must be an entry.")
164197
}

0 commit comments

Comments
 (0)