Skip to content

Commit 297a777

Browse files
committed
fix: add map directive parameters to parse payload without parsing
The parameters inside the map block were being treated as directives, thus not getting added to the parsed payload because they aren't in the allow list. This solves this issue by skipping further parsing or validating.
1 parent 7079cb5 commit 297a777

File tree

5 files changed

+229
-1
lines changed

5 files changed

+229
-1
lines changed

build_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ var compareFixtures = []compareFixture{
356356
{"empty-value-map", ParseOptions{}},
357357
{"russian-text", ParseOptions{}},
358358
{"quoted-right-brace", ParseOptions{}},
359-
{"directive-with-space", ParseOptions{}},
359+
{"directive-with-space", ParseOptions{ErrorOnUnknownDirectives: true}},
360360
{"empty-config", ParseOptions{}},
361361
}
362362

parse.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,23 @@ func (p *parser) parse(parsing *Config, tokens <-chan NgxToken, ctx blockCtx, co
260260
}
261261
}
262262

263+
// if inside map block - add contents to payload, but do not parse further
264+
if len(ctx) > 0 && (ctx[len(ctx)-1] == "map" || ctx[len(ctx)-1] == "charset_map") {
265+
mapErr := analyzeMapContents(parsing.File, stmt, t.Value)
266+
if mapErr != nil && p.options.StopParsingOnError {
267+
return nil, mapErr
268+
} else if mapErr != nil {
269+
p.handleError(parsing, mapErr)
270+
// consume invalid block
271+
if t.Value == "{" && !t.IsQuoted {
272+
_, _ = p.parse(parsing, tokens, nil, true)
273+
}
274+
continue
275+
}
276+
parsed = append(parsed, stmt)
277+
continue
278+
}
279+
263280
// consume the directive if it is ignored and move on
264281
if contains(p.options.IgnoreDirectives, stmt.Directive) {
265282
// if this directive was a block consume it too
@@ -417,3 +434,21 @@ func (p *parser) isAcyclic() bool {
417434
}
418435
return fileCount != len(p.includeInDegree)
419436
}
437+
438+
func analyzeMapContents(fname string, stmt *Directive, term string) error {
439+
if term != ";" {
440+
return &ParseError{
441+
What: fmt.Sprintf(`unexpected "%s"`, term),
442+
File: &fname,
443+
Line: &stmt.Line,
444+
}
445+
}
446+
if len(stmt.Args) != 1 {
447+
return &ParseError{
448+
What: "invalid number of the map parameters",
449+
File: &fname,
450+
Line: &stmt.Line,
451+
}
452+
}
453+
return nil
454+
}

parse_test.go

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,178 @@ var parseFixtures = []parseFixture{
907907
},
908908
},
909909
}},
910+
{"directive-with-space", "", ParseOptions{ErrorOnUnknownDirectives: true}, Payload{
911+
Status: "ok",
912+
Config: []Config{
913+
{
914+
File: getTestConfigPath("directive-with-space", "nginx.conf"),
915+
Status: "ok",
916+
Parsed: Directives{
917+
{
918+
Directive: "events",
919+
Args: []string{},
920+
Line: 1,
921+
Block: Directives{},
922+
},
923+
{
924+
Directive: "http",
925+
Args: []string{},
926+
Line: 3,
927+
Block: Directives{
928+
{
929+
Directive: "map",
930+
Args: []string{"$http_user_agent", "$mobile"},
931+
Line: 4,
932+
Block: Directives{
933+
{
934+
Directive: "default",
935+
Args: []string{"0"},
936+
Line: 5,
937+
Block: Directives{},
938+
},
939+
{
940+
Directive: "~Opera Mini",
941+
Args: []string{"1"},
942+
Line: 6,
943+
Block: Directives{},
944+
},
945+
},
946+
},
947+
{
948+
Directive: "charset_map",
949+
Args: []string{"koi8-r", "utf-8"},
950+
Line: 9,
951+
Block: Directives{
952+
{
953+
Directive: "C0",
954+
Args: []string{"D18E"},
955+
Line: 10,
956+
Block: Directives{},
957+
},
958+
{
959+
Directive: "C1",
960+
Args: []string{"D0B0"},
961+
Line: 11,
962+
Block: Directives{},
963+
},
964+
},
965+
},
966+
},
967+
},
968+
},
969+
},
970+
},
971+
}},
972+
{"invalid-map", "", ParseOptions{ErrorOnUnknownDirectives: true}, Payload{
973+
Status: "failed",
974+
Errors: []PayloadError{
975+
{
976+
File: getTestConfigPath("invalid-map", "nginx.conf"),
977+
Error: &ParseError{
978+
`unexpected "{"`,
979+
pStr(getTestConfigPath("invalid-map", "nginx.conf")),
980+
pInt(7),
981+
nil,
982+
},
983+
Line: pInt(7),
984+
},
985+
{
986+
File: getTestConfigPath("invalid-map", "nginx.conf"),
987+
Error: &ParseError{
988+
`invalid number of the map parameters`,
989+
pStr(getTestConfigPath("invalid-map", "nginx.conf")),
990+
pInt(10),
991+
nil,
992+
},
993+
Line: pInt(10),
994+
},
995+
{
996+
File: getTestConfigPath("invalid-map", "nginx.conf"),
997+
Error: &ParseError{
998+
`invalid number of the map parameters`,
999+
pStr(getTestConfigPath("invalid-map", "nginx.conf")),
1000+
pInt(14),
1001+
nil,
1002+
},
1003+
Line: pInt(14),
1004+
},
1005+
},
1006+
Config: []Config{
1007+
{
1008+
File: getTestConfigPath("invalid-map", "nginx.conf"),
1009+
Status: "failed",
1010+
Errors: []ConfigError{
1011+
{
1012+
Error: &ParseError{
1013+
`unexpected "{"`,
1014+
pStr(getTestConfigPath("invalid-map", "nginx.conf")),
1015+
pInt(7),
1016+
nil,
1017+
},
1018+
Line: pInt(7),
1019+
},
1020+
{
1021+
Error: &ParseError{
1022+
`invalid number of the map parameters`,
1023+
pStr(getTestConfigPath("invalid-map", "nginx.conf")),
1024+
pInt(10),
1025+
nil,
1026+
},
1027+
Line: pInt(10),
1028+
},
1029+
{
1030+
Error: &ParseError{
1031+
`invalid number of the map parameters`,
1032+
pStr(getTestConfigPath("invalid-map", "nginx.conf")),
1033+
pInt(14),
1034+
nil,
1035+
},
1036+
Line: pInt(14),
1037+
},
1038+
},
1039+
Parsed: Directives{
1040+
{
1041+
Directive: "events",
1042+
Args: []string{},
1043+
Line: 1,
1044+
Block: Directives{},
1045+
},
1046+
{
1047+
Directive: "http",
1048+
Args: []string{},
1049+
Line: 3,
1050+
Block: Directives{
1051+
{
1052+
Directive: "map",
1053+
Args: []string{"$http_user_agent", "$mobile"},
1054+
Line: 4,
1055+
Block: Directives{
1056+
{
1057+
Directive: "default",
1058+
Args: []string{"0"},
1059+
Line: 5,
1060+
Block: Directives{},
1061+
},
1062+
{
1063+
Directive: "~Opera Mini",
1064+
Args: []string{"1"},
1065+
Line: 6,
1066+
Block: Directives{},
1067+
},
1068+
},
1069+
},
1070+
{
1071+
Directive: "charset_map",
1072+
Args: []string{"koi8-r", "utf-8"},
1073+
Line: 13,
1074+
Block: Directives{},
1075+
},
1076+
},
1077+
},
1078+
},
1079+
},
1080+
},
1081+
}},
9101082
}
9111083

9121084
func TestParse(t *testing.T) {

testdata/configs/directive-with-space/nginx.conf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,9 @@ http {
55
default 0;
66
'~Opera Mini' 1;
77
}
8+
9+
charset_map koi8-r utf-8 {
10+
C0 D18E;
11+
C1 D0B0;
12+
}
813
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
events {
2+
}
3+
http {
4+
map $http_user_agent $mobile {
5+
default 0;
6+
'~Opera Mini' 1;
7+
i_am_lost {
8+
return 500;
9+
}
10+
too many params;
11+
}
12+
13+
charset_map koi8-r utf-8 {
14+
C0;
15+
}
16+
}

0 commit comments

Comments
 (0)