Skip to content

Commit 17caa24

Browse files
committed
NLB-3241: Export directive statement and block ctx causing parse error
- Allow visibility into the config statement causing a parse error. - Add exported field BlockCtx that holds the block of the context in which parse error occurs.
1 parent 1b4c902 commit 17caa24

File tree

7 files changed

+102
-40
lines changed

7 files changed

+102
-40
lines changed

analyze.go

+15-10
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,11 @@ func analyze(fname string, stmt *Directive, term string, ctx blockCtx, options *
9696
// if strict and directive isn't recognized then throw error
9797
if options.ErrorOnUnknownDirectives && !knownDirective {
9898
return &ParseError{
99-
What: fmt.Sprintf(`unknown directive "%s"`, stmt.Directive),
100-
File: &fname,
101-
Line: &stmt.Line,
99+
What: fmt.Sprintf(`unknown directive "%s"`, stmt.Directive),
100+
File: &fname,
101+
Line: &stmt.Line,
102+
Statement: stmt.String(),
103+
BlockCtx: ctx.getLastBlock(),
102104
}
103105
}
104106

@@ -120,9 +122,11 @@ func analyze(fname string, stmt *Directive, term string, ctx blockCtx, options *
120122
}
121123
if len(ctxMasks) == 0 && !options.SkipDirectiveContextCheck {
122124
return &ParseError{
123-
What: fmt.Sprintf(`"%s" directive is not allowed here`, stmt.Directive),
124-
File: &fname,
125-
Line: &stmt.Line,
125+
What: fmt.Sprintf(`"%s" directive is not allowed here`, stmt.Directive),
126+
File: &fname,
127+
Line: &stmt.Line,
128+
Statement: stmt.String(),
129+
BlockCtx: ctx.getLastBlock(),
126130
}
127131
}
128132
}
@@ -136,7 +140,6 @@ func analyze(fname string, stmt *Directive, term string, ctx blockCtx, options *
136140
var what string
137141
for i := 0; i < len(ctxMasks); i++ {
138142
mask := ctxMasks[i]
139-
140143
// if the directive is an expression type, there must be '(' 'expr' ')' args
141144
if (mask&ngxConfExpr) > 0 && !validExpr(stmt) {
142145
what = fmt.Sprintf(`directive "%s"'s is not enclosed in parentheses`, stmt.Directive)
@@ -171,9 +174,11 @@ func analyze(fname string, stmt *Directive, term string, ctx blockCtx, options *
171174
}
172175

173176
return &ParseError{
174-
What: what,
175-
File: &fname,
176-
Line: &stmt.Line,
177+
What: what,
178+
File: &fname,
179+
Line: &stmt.Line,
180+
Statement: stmt.String(),
181+
BlockCtx: ctx.getLastBlock(),
177182
}
178183
}
179184

analyze_map.go

+15-11
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,17 @@ var mapBodies = map[string]mapParameterMasks{
4444
// that don't contain nginx directives, and therefore cannot be analyzed in the same way as other blocks.
4545
func analyzeMapBody(fname string, parameter *Directive, term string, mapCtx string) error {
4646
masks, known := mapBodies[mapCtx]
47-
4847
// if we're not inside a known map-like directive, don't bother analyzing
4948
if !known {
5049
return nil
5150
}
52-
5351
if term != ";" {
5452
return &ParseError{
55-
What: fmt.Sprintf(`unexpected "%s"`, term),
56-
File: &fname,
57-
Line: &parameter.Line,
53+
What: fmt.Sprintf(`unexpected "%s"`, term),
54+
File: &fname,
55+
Line: &parameter.Line,
56+
Statement: parameter.String(),
57+
BlockCtx: mapCtx,
5858
}
5959
}
6060

@@ -65,9 +65,11 @@ func analyzeMapBody(fname string, parameter *Directive, term string, mapCtx stri
6565
}
6666

6767
return &ParseError{
68-
What: "invalid number of parameters",
69-
File: &fname,
70-
Line: &parameter.Line,
68+
What: "invalid number of parameters",
69+
File: &fname,
70+
Line: &parameter.Line,
71+
Statement: parameter.String(),
72+
BlockCtx: mapCtx,
7173
}
7274
}
7375

@@ -79,9 +81,11 @@ func analyzeMapBody(fname string, parameter *Directive, term string, mapCtx stri
7981
}
8082

8183
return &ParseError{
82-
What: "invalid number of parameters",
83-
File: &fname,
84-
Line: &parameter.Line,
84+
What: "invalid number of parameters",
85+
File: &fname,
86+
Line: &parameter.Line,
87+
Statement: parameter.String(),
88+
BlockCtx: mapCtx,
8589
}
8690
}
8791

analyze_map_test.go

+9-8
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func TestAnalyzeMapBody(t *testing.T) {
5151
Block: Directives{},
5252
},
5353
term: ";",
54-
wantErr: &ParseError{What: "invalid number of parameters"},
54+
wantErr: &ParseError{What: "invalid number of parameters", BlockCtx: "map"},
5555
},
5656
"valid map hostnames parameter": {
5757
mapDirective: "map",
@@ -71,7 +71,7 @@ func TestAnalyzeMapBody(t *testing.T) {
7171
Block: Directives{},
7272
},
7373
term: ";",
74-
wantErr: &ParseError{What: "invalid number of parameters"},
74+
wantErr: &ParseError{What: "invalid number of parameters", BlockCtx: "map"},
7575
},
7676
"valid geo proxy_recursive parameter": {
7777
mapDirective: "geo",
@@ -100,7 +100,7 @@ func TestAnalyzeMapBody(t *testing.T) {
100100
Block: Directives{},
101101
},
102102
term: ";",
103-
wantErr: &ParseError{What: "invalid number of parameters"},
103+
wantErr: &ParseError{What: "invalid number of parameters", BlockCtx: "types"},
104104
},
105105
"invalid geo proxy_recursive parameter": {
106106
mapDirective: "geo",
@@ -111,7 +111,7 @@ func TestAnalyzeMapBody(t *testing.T) {
111111
Block: Directives{},
112112
},
113113
term: ";",
114-
wantErr: &ParseError{What: "invalid number of parameters"},
114+
wantErr: &ParseError{What: "invalid number of parameters", BlockCtx: "geo"},
115115
},
116116
"valid geo ranges parameter": {
117117
mapDirective: "geo",
@@ -131,7 +131,7 @@ func TestAnalyzeMapBody(t *testing.T) {
131131
Block: Directives{},
132132
},
133133
term: ";",
134-
wantErr: &ParseError{What: "invalid number of parameters"},
134+
wantErr: &ParseError{What: "invalid number of parameters", BlockCtx: "geo"},
135135
},
136136
"invalid number of parameters in map": {
137137
mapDirective: "map",
@@ -142,7 +142,7 @@ func TestAnalyzeMapBody(t *testing.T) {
142142
Block: Directives{},
143143
},
144144
term: ";",
145-
wantErr: &ParseError{What: "invalid number of parameters"},
145+
wantErr: &ParseError{What: "invalid number of parameters", BlockCtx: "map"},
146146
},
147147
"valid split_clients": {
148148
mapDirective: "split_clients",
@@ -163,7 +163,7 @@ func TestAnalyzeMapBody(t *testing.T) {
163163
Block: Directives{},
164164
},
165165
term: ";",
166-
wantErr: &ParseError{What: "invalid number of parameters"},
166+
wantErr: &ParseError{What: "invalid number of parameters", BlockCtx: "split_clients"},
167167
},
168168
"missing semicolon": {
169169
mapDirective: "map",
@@ -174,7 +174,7 @@ func TestAnalyzeMapBody(t *testing.T) {
174174
Block: Directives{},
175175
},
176176
term: "}",
177-
wantErr: &ParseError{What: `unexpected "}"`},
177+
wantErr: &ParseError{What: `unexpected "}"`, BlockCtx: "map"},
178178
},
179179
}
180180

@@ -194,6 +194,7 @@ func TestAnalyzeMapBody(t *testing.T) {
194194
var perr *ParseError
195195
require.ErrorAs(t, err, &perr)
196196
require.Equal(t, tc.wantErr.What, perr.What)
197+
require.Equal(t, tc.wantErr.BlockCtx, perr.BlockCtx)
197198
})
198199
}
199200
}

errors.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@ import (
1313
)
1414

1515
type ParseError struct {
16-
What string
17-
File *string
18-
Line *int
16+
What string
17+
File *string
18+
Line *int
19+
// Raw directive statement causing the parse error.
20+
Statement string
21+
// Block in which parse error occurred.
22+
BlockCtx string
1923
originalErr error
2024
}
2125

parse.go

+20-5
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ func (c blockCtx) key() string {
3131
return strings.Join(c, ">")
3232
}
3333

34+
func (c blockCtx) getLastBlock() string {
35+
if len(c) == 0 {
36+
return "main"
37+
}
38+
return c[len(c)-1]
39+
}
40+
3441
type fileCtx struct {
3542
path string
3643
ctx blockCtx
@@ -191,13 +198,15 @@ func (p *parser) parse(parsing *Config, tokens <-chan NgxToken, ctx blockCtx, co
191198
var perr *ParseError
192199
if errors.As(t.Error, &perr) {
193200
perr.File = &parsing.File
201+
perr.BlockCtx = ctx.getLastBlock()
194202
return nil, perr
195203
}
196204
return nil, &ParseError{
197205
What: t.Error.Error(),
198206
File: &parsing.File,
199207
Line: &t.Line,
200208
originalErr: t.Error,
209+
BlockCtx: ctx.getLastBlock(),
201210
}
202211
}
203212

@@ -249,6 +258,7 @@ func (p *parser) parse(parsing *Config, tokens <-chan NgxToken, ctx blockCtx, co
249258
File: &parsing.File,
250259
Line: &stmt.Line,
251260
originalErr: ErrPrematureLexEnd,
261+
BlockCtx: ctx.getLastBlock(),
252262
}
253263
}
254264
for t.IsQuoted || (t.Value != "{" && t.Value != ";" && t.Value != "}") {
@@ -264,6 +274,7 @@ func (p *parser) parse(parsing *Config, tokens <-chan NgxToken, ctx blockCtx, co
264274
File: &parsing.File,
265275
Line: &stmt.Line,
266276
originalErr: ErrPrematureLexEnd,
277+
BlockCtx: ctx.getLastBlock(),
267278
}
268279
}
269280
}
@@ -329,8 +340,10 @@ func (p *parser) parse(parsing *Config, tokens <-chan NgxToken, ctx blockCtx, co
329340
parsing.File,
330341
stmt.Line,
331342
),
332-
File: &parsing.File,
333-
Line: &stmt.Line,
343+
File: &parsing.File,
344+
Line: &stmt.Line,
345+
Statement: stmt.String(),
346+
BlockCtx: ctx.getLastBlock(),
334347
}
335348
}
336349

@@ -352,9 +365,11 @@ func (p *parser) parse(parsing *Config, tokens <-chan NgxToken, ctx blockCtx, co
352365
// that the included file can be opened and read
353366
if f, err := p.openFile(pattern); err != nil {
354367
perr := &ParseError{
355-
What: err.Error(),
356-
File: &parsing.File,
357-
Line: &stmt.Line,
368+
What: err.Error(),
369+
File: &parsing.File,
370+
Line: &stmt.Line,
371+
Statement: stmt.String(),
372+
BlockCtx: ctx.getLastBlock(),
358373
}
359374
if !p.options.StopParsingOnError {
360375
p.handleError(parsing, perr)

0 commit comments

Comments
 (0)