Update OpenAPI path parsing of alternation parameters (#5710)

This will handle patterns of the form:
  `^plugins/catalog/(?P<type>auth|database|secret)/(?P<name>.+)$`
This commit is contained in:
Jim Kalafut 2018-11-06 15:04:30 -08:00 committed by GitHub
parent 1a31603dcf
commit 583003cf42
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 31 additions and 7 deletions

View File

@ -177,12 +177,14 @@ var OASStdRespNoContent = &OASResponse{
// Both "(leases/)?renew" and "(/(?P<name>.+))?" formats are detected
var optRe = regexp.MustCompile(`(?U)\([^(]*\)\?|\(/\(\?P<[^(]*\)\)\?`)
var reqdRe = regexp.MustCompile(`\(?\?P<(\w+)>[^)]*\)?`) // Capture required parameters, e.g. "(?P<name>regex)"
var altRe = regexp.MustCompile(`\((.*)\|(.*)\)`) // Capture alternation elements, e.g. "(raw/?$|raw/(?P<path>.+))"
var pathFieldsRe = regexp.MustCompile(`{(\w+)}`) // Capture OpenAPI-style named parameters, e.g. "lookup/{urltoken}",
var cleanCharsRe = regexp.MustCompile("[()^$?]") // Set of regex characters that will be stripped during cleaning
var cleanSuffixRe = regexp.MustCompile(`/\?\$?$`) // Path suffix patterns that will be stripped during cleaning
var wsRe = regexp.MustCompile(`\s+`) // Match whitespace, to be compressed during cleaning
var reqdRe = regexp.MustCompile(`\(?\?P<(\w+)>[^)]*\)?`) // Capture required parameters, e.g. "(?P<name>regex)"
var altRe = regexp.MustCompile(`\((.*)\|(.*)\)`) // Capture alternation elements, e.g. "(raw/?$|raw/(?P<path>.+))"
var pathFieldsRe = regexp.MustCompile(`{(\w+)}`) // Capture OpenAPI-style named parameters, e.g. "lookup/{urltoken}",
var cleanCharsRe = regexp.MustCompile("[()^$?]") // Set of regex characters that will be stripped during cleaning
var cleanSuffixRe = regexp.MustCompile(`/\?\$?$`) // Path suffix patterns that will be stripped during cleaning
var wsRe = regexp.MustCompile(`\s+`) // Match whitespace, to be compressed during cleaning
var altFieldsGroupRe = regexp.MustCompile(`\(\?P<\w+>\w+(\|\w+)+\)`) // Match named groups that limit options, e.g. "(?<foo>a|b|c)"
var altFieldsRe = regexp.MustCompile(`\w+(\|\w+)+`) // Match an options set, e.g. "a|b|c"
// documentPaths parses all paths in a framework.Backend into OpenAPI paths.
func documentPaths(backend *Backend, doc *OASDocument) error {
@ -446,9 +448,13 @@ func expandPattern(pattern string) []string {
if start != -1 && end != -1 && end > start {
regexToRemove = base[start+1 : end]
}
pattern = strings.Replace(pattern, regexToRemove, "", -1)
// Simplify named fields that have limited options, e.g. (?P<foo>a|b|c) -> (<P<foo>.+)
pattern = altFieldsGroupRe.ReplaceAllStringFunc(pattern, func(s string) string {
return altFieldsRe.ReplaceAllString(s, ".+")
})
// Initialize paths with the original pattern or the halves of an
// alternation, which is also present in some patterns.
matches := altRe.FindAllStringSubmatch(pattern, -1)

View File

@ -74,6 +74,18 @@ func TestOpenAPI_Regex(t *testing.T) {
t.Fatalf("Expected nil match (%s), got %+v", input, matches)
}
})
t.Run("Alternation Fields", func(t *testing.T) {
input := `/foo/bar/(?P<type>auth|database|secret)/(?P<blah>a|b)`
act := altFieldsGroupRe.ReplaceAllStringFunc(input, func(s string) string {
return altFieldsRe.ReplaceAllString(s, ".+")
})
exp := "/foo/bar/(?P<type>.+)/(?P<blah>.+)"
if act != exp {
t.Fatalf("Replace error. Expected %s, got %v", exp, act)
}
})
t.Run("Path fields", func(t *testing.T) {
input := `/foo/bar/{inner}/baz/{outer}`
@ -180,6 +192,12 @@ func TestOpenAPI_ExpandPattern(t *testing.T) {
"verify/{name}",
"verify/{name}/{urlalgorithm}",
}},
{"^plugins/catalog/(?P<type>auth|database|secret)/(?P<name>.+)$", []string{
"plugins/catalog/{type}/{name}",
}},
{"^plugins/catalog/(?P<type>auth|database|secret)/?$", []string{
"plugins/catalog/{type}",
}},
}
for i, test := range tests {