Repository: ogen-go/ogen
Pull request #512 (2022-08-01 07:51:27)

fix(gen): do not allow two path parameters in a row


Patch:
diff --git a/gen/route_tree.go b/gen/route_tree.go
index 3bb2a9e7..969079b9 100644
--- a/gen/route_tree.go
+++ b/gen/route_tree.go
@@ -1,10 +1,6 @@
 package gen
 
 import (
-	"unicode/utf8"
-
-	"github.com/go-faster/errors"
-
 	"github.com/ogen-go/ogen/gen/ir"
 )
 
@@ -42,9 +38,6 @@ func longestPrefix(k1, k2 string) int {
 
 func (t *RouteTree) addRoute(m Route) error {
 	path := m.Path
-	if !utf8.ValidString(path) {
-		return errors.New("invalid path: path must be valid UTF-8 string")
-	}
 
 	n := t.Root
 	if n == nil {
diff --git a/gen/router.go b/gen/router.go
index 44aa9905..587fe396 100644
--- a/gen/router.go
+++ b/gen/router.go
@@ -7,6 +7,7 @@ import (
 	"github.com/go-faster/errors"
 
 	"github.com/ogen-go/ogen/gen/ir"
+	"github.com/ogen-go/ogen/openapi"
 )
 
 // Route describes route.
@@ -59,16 +60,42 @@ func (s *Router) Add(r Route) error {
 	return s.Tree.addRoute(r)
 }
 
+func checkRoutePath(p openapi.Path) error {
+	for i, part := range p {
+		if i == 0 {
+			continue
+		}
+		// Cond: i > 0
+		current := part.Param
+		prev := p[i-1].Param
+		if prev != nil && current != nil {
+			return errors.Errorf(
+				"can't handle two parameters in a row (%q and %q)",
+				prev.Name, current.Name,
+			)
+		}
+	}
+	return nil
+}
+
 func (g *Generator) route() error {
 	var maxParametersCount int
 	for _, op := range g.operations {
-		if err := g.router.Add(Route{
-			Method:    strings.ToUpper(op.Spec.HTTPMethod),
-			Path:      op.Spec.Path.String(),
-			Operation: op,
-		}); err != nil {
-			return errors.Wrapf(err, "add route %q", op.Name)
+		path := op.Spec.Path
+
+		if err := func() error {
+			if err := checkRoutePath(path); err != nil {
+				return err
+			}
+			return g.router.Add(Route{
+				Method:    strings.ToUpper(op.Spec.HTTPMethod),
+				Path:      path.String(),
+				Operation: op,
+			})
+		}(); err != nil {
+			return errors.Wrapf(err, "add route %q (op %q)", path, op.Name)
 		}
+
 		if count := op.PathParamsCount(); maxParametersCount < count {
 			maxParametersCount = count
 		}
diff --git a/openapi/parser/path_parser.go b/openapi/parser/path_parser.go
index 9a97cfc8..b7cc23f9 100644
--- a/openapi/parser/path_parser.go
+++ b/openapi/parser/path_parser.go
@@ -3,6 +3,7 @@ package parser
 import (
 	"net/url"
 	"strings"
+	"unicode/utf8"
 
 	"github.com/go-faster/errors"
 
@@ -51,6 +52,10 @@ func (p *pathParser) Parse() (openapi.Path, error) {
 }
 
 func (p *pathParser) parse() error {
+	if !utf8.ValidString(p.path) {
+		return errors.New("path must be valid UTF-8 string")
+	}
+
 	// Validate and unescape path.
 	//
 	// FIXME(tdakkota): OpenAPI spec, as always, is not clear about path validation.


Test patch:
diff --git a/_testdata/negative/router/two_parameter_in_a_row.json b/_testdata/negative/router/two_parameter_in_a_row.json
new file mode 100644
index 00000000..71039ff5
--- /dev/null
+++ b/_testdata/negative/router/two_parameter_in_a_row.json
@@ -0,0 +1,36 @@
+{
+  "openapi": "3.0.3",
+  "info": {
+    "title": "title",
+    "version": "v0.1.0"
+  },
+  "paths": {
+    "/root/{a}{b}": {
+      "get": {
+        "parameters": [
+          {
+            "name": "a",
+            "in": "path",
+            "required": true,
+            "schema": {
+              "type": "string"
+            }
+          },
+          {
+            "name": "b",
+            "in": "path",
+            "required": true,
+            "schema": {
+              "type": "string"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "User info"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/openapi/parser/path_parser_test.go b/openapi/parser/path_parser_test.go
index 71ba14ad..af3638e0 100644
--- a/openapi/parser/path_parser_test.go
+++ b/openapi/parser/path_parser_test.go
@@ -63,6 +63,10 @@ func TestPathParser(t *testing.T) {
 				{Raw: "/foo bar"},
 			},
 		},
+		{
+			Path:      "\xF1",
+			ExpectErr: `path must be valid UTF-8 string`,
+		},
 		{
 			Path:      "\x00",
 			ExpectErr: `parse "\x00": net/url: invalid control character in URL`,