mirror of
https://github.com/zeromicro/go-zero.git
synced 2026-05-07 15:10:01 +08:00
fix: allow special characters like periods in API route paths (#4827)
This commit is contained in:
@@ -465,6 +465,20 @@ func (p *Parser) parsePathItem() []token.Token {
|
||||
if !p.advanceIfPeekTokenIs(token.IDENT) {
|
||||
return nil
|
||||
}
|
||||
list = append(list, p.curTok)
|
||||
} else if p.peekTokenIs(token.DOT) {
|
||||
// Allow dot (.) in path segments for file extensions like .php, .html, etc.
|
||||
if !p.nextToken() {
|
||||
return nil
|
||||
}
|
||||
|
||||
list = append(list, p.curTok)
|
||||
|
||||
// After a dot, we expect an identifier (e.g., .php, .html)
|
||||
if !p.advanceIfPeekTokenIs(token.IDENT) {
|
||||
return nil
|
||||
}
|
||||
|
||||
list = append(list, p.curTok)
|
||||
} else {
|
||||
if p.peekTokenIs(token.LPAREN, token.Returns, token.AT_DOC, token.AT_HANDLER, token.SEMICOLON, token.RBRACE) {
|
||||
|
||||
@@ -760,11 +760,6 @@ func TestParser_Parse_service(t *testing.T) {
|
||||
}),
|
||||
},
|
||||
Request: &ast.BodyStmt{
|
||||
LParen: ast.NewTokenNode(token.Token{Type: token.LPAREN, Text: "("}),
|
||||
RParen: ast.NewTokenNode(token.Token{Type: token.RPAREN, Text: ")"}),
|
||||
},
|
||||
Returns: ast.NewTokenNode(token.Token{Type: token.IDENT, Text: "returns"}),
|
||||
Response: &ast.BodyStmt{
|
||||
LParen: ast.NewTokenNode(token.Token{Type: token.LPAREN, Text: "("}),
|
||||
Body: &ast.BodyExpr{
|
||||
Value: ast.NewTokenNode(token.Token{Type: token.IDENT, Text: "Foo"}),
|
||||
@@ -1031,6 +1026,7 @@ func TestParser_Parse_pathItem(t *testing.T) {
|
||||
{input: "1", expected: "1"},
|
||||
{input: "11", expected: "11"},
|
||||
}
|
||||
|
||||
for _, v := range testData {
|
||||
p := New("foo.api", v.input)
|
||||
ok := p.nextToken()
|
||||
@@ -1066,6 +1062,38 @@ func TestParser_Parse_pathItem(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestParser_Parse_pathItem_WithDot(t *testing.T) {
|
||||
t.Run("valid with dots", func(t *testing.T) {
|
||||
var testData = []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{input: "file.php", expected: "file.php"},
|
||||
{input: "api_jsonrpc.php", expected: "api_jsonrpc.php"},
|
||||
{input: "index.html", expected: "index.html"},
|
||||
{input: "data.json", expected: "data.json"},
|
||||
{input: "style.css", expected: "style.css"},
|
||||
{input: "script.js", expected: "script.js"},
|
||||
{input: "document.pdf", expected: "document.pdf"},
|
||||
{input: "image.png", expected: "image.png"},
|
||||
{input: "api.v1", expected: "api.v1"},
|
||||
{input: "resource.with.multiple.dots", expected: "resource.with.multiple.dots"},
|
||||
}
|
||||
|
||||
for _, v := range testData {
|
||||
p := New("foo.api", v.input)
|
||||
ok := p.nextToken()
|
||||
assert.True(t, ok)
|
||||
tokens := p.parsePathItem()
|
||||
var expected []string
|
||||
for _, tok := range tokens {
|
||||
expected = append(expected, tok.Text)
|
||||
}
|
||||
assert.Equal(t, strings.Join(expected, ""), v.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestParser_Parse_parseTypeStmt(t *testing.T) {
|
||||
assertEqual := func(t *testing.T, expected, actual ast.Stmt) {
|
||||
if expected == nil {
|
||||
@@ -1399,6 +1427,7 @@ func TestParser_Parse_parseTypeStmt(t *testing.T) {
|
||||
assertEqual(t, val.expected, one)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("parseTypeGroupStmt", func(t *testing.T) {
|
||||
var testData = []struct {
|
||||
input string
|
||||
@@ -1472,6 +1501,7 @@ func TestParser_Parse_parseTypeStmt(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, val := range testData {
|
||||
p := New("test.api", val.input)
|
||||
result := p.Parse()
|
||||
|
||||
Reference in New Issue
Block a user