Skip to content

Commit

Permalink
Fix templateToSwaggerPath generates invalid path
Browse files Browse the repository at this point in the history
  • Loading branch information
ch3rub1m committed Oct 21, 2019
1 parent 8115cdb commit 163bea8
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 13 deletions.
35 changes: 32 additions & 3 deletions protoc-gen-swagger/genswagger/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package genswagger
import (
"encoding/json"
"fmt"
"net/url"
"os"
"reflect"
"regexp"
Expand All @@ -14,9 +15,9 @@ import (
"github.com/golang/glog"
"github.com/golang/protobuf/jsonpb"
"github.com/golang/protobuf/proto"
structpb "github.com/golang/protobuf/ptypes/struct"
pbdescriptor "github.com/golang/protobuf/protoc-gen-go/descriptor"
gogen "github.com/golang/protobuf/protoc-gen-go/generator"
structpb "github.com/golang/protobuf/ptypes/struct"
"github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor"
swagger_options "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options"
)
Expand Down Expand Up @@ -675,13 +676,18 @@ func templateToSwaggerPath(path string, reg *descriptor.Registry) string {
// Parts is now an array of segments of the path. Interestingly, since the
// syntax for this subsection CAN be handled by a regexp since it has no
// memory.
keyre := regexp.MustCompile("{(.*)}")
for index, part := range parts {
// If part is a resource name such as "parent", "name", "user.name", the format info must be retained.
prefix := canRegexp.ReplaceAllString(part, "$1")
if isResourceName(prefix) {
continue
sm := keyre.FindStringSubmatch(part)
key := sm[1]
esckey := url.PathEscape(key)
parts[index] = keyre.ReplaceAllString(part, fmt.Sprintf("{%s}", esckey))
} else {
parts[index] = canRegexp.ReplaceAllString(part, "{$1}")
}
parts[index] = canRegexp.ReplaceAllString(part, "{$1}")
}

return strings.Join(parts, "/")
Expand All @@ -696,11 +702,31 @@ func isResourceName(prefix string) bool {
return field == "parent" || field == "name"
}

func extractResourceName(path string) map[string]string {
m := map[string]string{}
keyre := regexp.MustCompile("{(.*)}")
sm := keyre.FindStringSubmatch(path)
count := len(sm)
for i := 0; i < count; i++ {
key := sm[1]
parts := strings.Split(key, "=")
label := parts[0]
parts = strings.Split(label, ".")
l := len(parts)
field := parts[l-1]
if field == "parent" || field == "name" {
m[label] = key
}
}
return m
}

func renderServices(services []*descriptor.Service, paths swaggerPathsObject, reg *descriptor.Registry, requestResponseRefs, customRefs refMap) error {
// Correctness of svcIdx and methIdx depends on 'services' containing the services in the same order as the 'file.Service' array.
for svcIdx, svc := range services {
for methIdx, meth := range svc.Methods {
for bIdx, b := range meth.Bindings {
pathParamMap := extractResourceName(templateToSwaggerPath(b.PathTmpl.Template, reg))
// Iterate over all the swagger parameters
parameters := swaggerParametersObject{}
for _, parameter := range b.PathParams {
Expand Down Expand Up @@ -768,6 +794,9 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re
if reg.GetUseJSONNamesForFields() {
parameterString = lowerCamelCase(parameterString)
}
if esckey, ok := pathParamMap[parameterString]; ok {
parameterString = esckey
}
parameters = append(parameters, swaggerParameterObject{
Name: parameterString,
Description: desc,
Expand Down
21 changes: 11 additions & 10 deletions protoc-gen-swagger/genswagger/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1050,16 +1050,17 @@ func TestTemplateToSwaggerPath(t *testing.T) {
{"/{test=prefix/that/has/multiple/parts/to/it/*}", "/{test}"},
{"/{test1}/{test2}", "/{test1}/{test2}"},
{"/{test1}/{test2}/", "/{test1}/{test2}/"},
{"/{name=prefix/*}", "/{name=prefix/*}"},
{"/{name=prefix1/*/prefix2/*}", "/{name=prefix1/*/prefix2/*}"},
{"/{user.name=prefix/*}", "/{user.name=prefix/*}"},
{"/{user.name=prefix1/*/prefix2/*}", "/{user.name=prefix1/*/prefix2/*}"},
{"/{parent=prefix/*}/children", "/{parent=prefix/*}/children"},
{"/{name=prefix/*}:customMethod", "/{name=prefix/*}:customMethod"},
{"/{name=prefix1/*/prefix2/*}:customMethod", "/{name=prefix1/*/prefix2/*}:customMethod"},
{"/{user.name=prefix/*}:customMethod", "/{user.name=prefix/*}:customMethod"},
{"/{user.name=prefix1/*/prefix2/*}:customMethod", "/{user.name=prefix1/*/prefix2/*}:customMethod"},
{"/{parent=prefix/*}/children:customMethod", "/{parent=prefix/*}/children:customMethod"},
{"/{name=prefix/*}", "/{name=prefix%2F%2A}"},
{"/{name=prefix1/*/prefix2/*}", "/{name=prefix1%2F%2A%2Fprefix2%2F%2A}"},
{"/{parent=prefix1/*}/{name=prefix2/*}", "/{parent=prefix1%2F%2A}/{name=prefix2%2F%2A}"},
{"/{user.name=prefix/*}", "/{user.name=prefix%2F%2A}"},
{"/{user.name=prefix1/*/prefix2/*}", "/{user.name=prefix1%2F%2A%2Fprefix2%2F%2A}"},
{"/{parent=prefix/*}/children", "/{parent=prefix%2F%2A}/children"},
{"/{name=prefix/*}:customMethod", "/{name=prefix%2F%2A}:customMethod"},
{"/{name=prefix1/*/prefix2/*}:customMethod", "/{name=prefix1%2F%2A%2Fprefix2%2F%2A}:customMethod"},
{"/{user.name=prefix/*}:customMethod", "/{user.name=prefix%2F%2A}:customMethod"},
{"/{user.name=prefix1/*/prefix2/*}:customMethod", "/{user.name=prefix1%2F%2A%2Fprefix2%2F%2A}:customMethod"},
{"/{parent=prefix/*}/children:customMethod", "/{parent=prefix%2F%2A}/children:customMethod"},
}
reg := descriptor.NewRegistry()
reg.SetUseJSONNamesForFields(false)
Expand Down

0 comments on commit 163bea8

Please sign in to comment.