Skip to content

Commit 7dbcffb

Browse files
authored
Merge pull request #45 from CiscoM31/case-statement
Add additional $select and $expand query validation
2 parents 11c3954 + 854afe1 commit 7dbcffb

File tree

5 files changed

+70
-17
lines changed

5 files changed

+70
-17
lines changed

.github/workflows/golangci-lint.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
uses: golangci/golangci-lint-action@v2
1515
with:
1616
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
17-
version: v1.53.3
17+
version: v1.55.2
1818

1919
# Optional: working directory, useful for monorepos
2020
# working-directory: somedir

expand_parser.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,14 @@ func ParseExpandItem(ctx context.Context, input tokenQueue) (*ExpandItem, error)
139139
queue = &tokenQueue{}
140140
}
141141
} else if token.Value == "/" && stack.Empty() {
142+
if queue.Empty() {
143+
// Disallow extra leading and intermediate slash, like /Product and Product//Info
144+
return nil, BadRequestError("Empty path segment in expand clause.")
145+
}
146+
if input.Empty() {
147+
// Disallow extra trailing slash, like Product/
148+
return nil, BadRequestError("Empty path segment in expand clause.")
149+
}
142150
// at root level, slashes separate path segments
143151
item.Path = append(item.Path, queue.Dequeue())
144152
} else if token.Value == ";" && stack.Size == 1 {

expand_parser_test.go

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -123,16 +123,27 @@ func TestExpandNestedParens(t *testing.T) {
123123
}
124124

125125
func TestExpandNegativeCases(t *testing.T) {
126-
input := "Products," // Extraneous comma
127-
ctx := context.Background()
128-
output, err := ParseExpandString(ctx, input)
129-
130-
if err == nil {
131-
t.Error("Expected parsing to return error.")
132-
return
133-
}
134-
if output != nil {
135-
t.Error("Expected parsing to return nil output.")
136-
return
126+
testcases := []string{
127+
"Products,", // Extraneous comma
128+
"Products//Data", // Double slash
129+
"/Products", // Extraneous leading slash
130+
"Products/", // Extraneous trailing slash
131+
"Orders,/Products", // Extraneous leading slash
132+
"Products/,Orders", // Extraneous trailing slash
133+
}
134+
135+
for _, testcase := range testcases {
136+
t.Logf("Expand: %s", testcase)
137+
ctx := context.Background()
138+
output, err := ParseExpandString(ctx, testcase)
139+
140+
if err == nil {
141+
t.Error("Expected parsing to return error.")
142+
return
143+
}
144+
if output != nil {
145+
t.Error("Expected parsing to return nil output.")
146+
return
147+
}
137148
}
138149
}

select_parser.go

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,16 @@ type SelectItem struct {
1111
}
1212

1313
func ParseSelectString(ctx context.Context, sel string) (*GoDataSelectQuery, error) {
14+
return GlobalExpressionParser.ParseSelectString(ctx, sel)
15+
}
16+
17+
func (p *ExpressionParser) ParseSelectString(ctx context.Context, sel string) (*GoDataSelectQuery, error) {
1418
items := strings.Split(sel, ",")
1519

1620
result := []*SelectItem{}
1721

1822
for _, item := range items {
23+
item = strings.TrimSpace(item)
1924

2025
cfg, hasComplianceConfig := ctx.Value(odataCompliance).(OdataComplianceConfig)
2126
if !hasComplianceConfig {
@@ -27,11 +32,28 @@ func ParseSelectString(ctx context.Context, sel string) (*GoDataSelectQuery, err
2732
return nil, BadRequestError("Extra comma in $select.")
2833
}
2934

30-
segments := []*Token{}
31-
for _, val := range strings.Split(item, "/") {
32-
segments = append(segments, &Token{Value: val})
35+
if _, err := p.tokenizer.Tokenize(ctx, item); err != nil {
36+
switch e := err.(type) {
37+
case *GoDataError:
38+
return nil, &GoDataError{
39+
ResponseCode: e.ResponseCode,
40+
Message: "Invalid $select value",
41+
Cause: e,
42+
}
43+
default:
44+
return nil, &GoDataError{
45+
ResponseCode: 500,
46+
Message: "Invalid $select value",
47+
Cause: e,
48+
}
49+
}
50+
} else {
51+
segments := []*Token{}
52+
for _, val := range strings.Split(item, "/") {
53+
segments = append(segments, &Token{Value: val})
54+
}
55+
result = append(result, &SelectItem{segments})
3356
}
34-
result = append(result, &SelectItem{segments})
3557
}
3658

3759
return &GoDataSelectQuery{result, sel}, nil

url_parser_test.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ func TestUrlParserStrictValidation(t *testing.T) {
119119
return
120120
}
121121

122-
testUrl = "Employees(1)/Sales.Manager?$filter=Name in ('Bob','Alice')&$select=Name,Address%3B$expand=Address($select=City)"
122+
testUrl = "Employees(1)/Sales.Manager?$filter=Name in ('Bob','Alice')&$select=Name,Address&$expand=Address($select=City)"
123123
parsedUrl, err = url.Parse(testUrl)
124124
if err != nil {
125125
t.Error(err)
@@ -530,6 +530,18 @@ func TestUnescapeStringTokens(t *testing.T) {
530530
expectedFilterTree: nil,
531531
expectedOrderBy: nil,
532532
},
533+
{
534+
url: "/Product?$select=$select=Name",
535+
errRegex: regexp.MustCompile(`Invalid \$select\ value.`),
536+
expectedFilterTree: nil,
537+
expectedOrderBy: nil,
538+
},
539+
{
540+
url: "/Product?$select=$Name",
541+
errRegex: regexp.MustCompile(`Invalid \$select\ value.`),
542+
expectedFilterTree: nil,
543+
expectedOrderBy: nil,
544+
},
533545
{
534546
url: "/Product?$compute=Price mul Quantity as TotalPrice",
535547
errRegex: nil,

0 commit comments

Comments
 (0)