diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConfig.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConfig.java index 694377a1d83..3cc6fc776b8 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConfig.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConfig.java @@ -81,6 +81,8 @@ public interface CodegenConfig { String escapeTextWhileAllowingNewLines(String text); + String encodePath(String text); + String escapeUnsafeCharacters(String input); String escapeReservedWord(String name); diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index 32a16ec7f60..e02cb08984c 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -557,6 +557,12 @@ public class DefaultCodegen implements CodegenConfig { .replace("\"", "\\\"")); } + // override with any special encoding and escaping logic + @SuppressWarnings("static-method") + public String encodePath(String input) { + return escapeText(input); + } + /** * override with any special text escaping logic to handle unsafe * characters so as to avoid code injection diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java index 36d759d9e6c..1a0791395ed 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultGenerator.java @@ -537,9 +537,9 @@ public class DefaultGenerator extends AbstractGenerator implements Generator { } }); Map operation = processOperations(config, tag, ops, allModels); - + URL url = URLPathUtils.getServerURL(openAPI); operation.put("basePath", basePath); - operation.put("basePathWithoutHost", basePathWithoutHost); + operation.put("basePathWithoutHost", config.encodePath(url.getPath()).replaceAll("/$", "")); operation.put("contextPath", contextPath); operation.put("baseName", tag); operation.put("apiPackage", config.apiPackage()); diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PhpSlimServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PhpSlimServerCodegen.java index d8480e4cc9e..34e971f6073 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PhpSlimServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PhpSlimServerCodegen.java @@ -31,6 +31,13 @@ import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.net.URLEncoder; +import org.apache.commons.lang3.StringEscapeUtils; +import java.io.UnsupportedEncodingException; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.media.Schema; public class PhpSlimServerCodegen extends AbstractPhpCodegen { private static final Logger LOGGER = LoggerFactory.getLogger(PhpSlimServerCodegen.class); @@ -179,4 +186,57 @@ public class PhpSlimServerCodegen extends AbstractPhpCodegen { operations.put(USER_CLASSNAME_KEY, classname); } + @Override + public String encodePath(String input) { + if (input == null) { + return input; + } + + // from DefaultCodegen.java + // remove \t, \n, \r + // replace \ with \\ + // replace " with \" + // outter unescape to retain the original multi-byte characters + // finally escalate characters avoiding code injection + input = super.escapeUnsafeCharacters( + StringEscapeUtils.unescapeJava( + StringEscapeUtils.escapeJava(input) + .replace("\\/", "/")) + .replaceAll("[\\t\\n\\r]", " ") + .replace("\\", "\\\\")); + // .replace("\"", "\\\"")); + + // from AbstractPhpCodegen.java + // Trim the string to avoid leading and trailing spaces. + input = input.trim(); + try { + + input = URLEncoder.encode(input, "UTF-8") + .replaceAll("\\+", "%20") + .replaceAll("\\%2F", "/") + .replaceAll("\\%7B", "{") // keep { part of complex placeholders + .replaceAll("\\%7D", "}") // } part + .replaceAll("\\%5B", "[") // [ part + .replaceAll("\\%5D", "]") // ] part + .replaceAll("\\%3A", ":") // : part + .replaceAll("\\%2B", "+") // + part + .replaceAll("\\%5C\\%5Cd", "\\\\d"); // \d part + } catch (UnsupportedEncodingException e) { + // continue + LOGGER.error(e.getMessage(), e); + } + return input; + } + + @Override + public CodegenOperation fromOperation(String path, + String httpMethod, + Operation operation, + Map schemas, + OpenAPI openAPI) { + CodegenOperation op = super.fromOperation(path, httpMethod, operation, schemas, openAPI); + op.path = encodePath(path); + return op; + } + } diff --git a/modules/openapi-generator/src/main/resources/php-slim-server/SlimRouter.mustache b/modules/openapi-generator/src/main/resources/php-slim-server/SlimRouter.mustache index c68b2b2022c..09b8925e9a3 100644 --- a/modules/openapi-generator/src/main/resources/php-slim-server/SlimRouter.mustache +++ b/modules/openapi-generator/src/main/resources/php-slim-server/SlimRouter.mustache @@ -64,7 +64,7 @@ class SlimRouter [ 'httpMethod' => '{{httpMethod}}', 'basePathWithoutHost' => '{{{basePathWithoutHost}}}', - 'path' => '{{path}}', + 'path' => '{{{path}}}', 'apiPackage' => '{{apiPackage}}', 'classname' => '{{classname}}', 'userClassname' => '{{userClassname}}', diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/slim/PhpSlimServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/slim/PhpSlimServerCodegenTest.java new file mode 100644 index 00000000000..329b5e9195f --- /dev/null +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/slim/PhpSlimServerCodegenTest.java @@ -0,0 +1,47 @@ +/* + * Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openapitools.codegen.slim; + +import org.testng.Assert; +import org.testng.annotations.Test; + +import org.openapitools.codegen.languages.PhpSlimServerCodegen; + +public class PhpSlimServerCodegenTest { + + @Test + public void testEncodePath() { + final PhpSlimServerCodegen codegen = new PhpSlimServerCodegen(); + + Assert.assertEquals(codegen.encodePath("/ ' \" =end -- \\r\\n \\n \\r/v2 *_/ ' \" =end -- \\r\\n \\n \\r/fake"), "/%20%27%20%22%20%3Dend%20--%20%5C%5Cr%5C%5Cn%20%5C%5Cn%20%5C%5Cr/v2%20*_/%20%27%20%22%20%3Dend%20--%20%5C%5Cr%5C%5Cn%20%5C%5Cn%20%5C%5Cr/fake"); + Assert.assertEquals(codegen.encodePath("/o\'\"briens/v2/o\'\"henry/fake"), "/o%27%22briens/v2/o%27%22henry/fake"); + Assert.assertEquals(codegen.encodePath("/comedians/Chris D\'Elia"), "/comedians/Chris%20D%27Elia"); + Assert.assertEquals(codegen.encodePath("/разработчики/Юрий Беленко"), "/%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%87%D0%B8%D0%BA%D0%B8/%D0%AE%D1%80%D0%B8%D0%B9%20%D0%91%D0%B5%D0%BB%D0%B5%D0%BD%D0%BA%D0%BE"); + Assert.assertEquals(codegen.encodePath("/text with multilines \\\n\\\t\\\r"), "/text%20with%20multilines%20%5C%5C%20%5C%5C%20%5C%5C"); + Assert.assertEquals(codegen.encodePath("/path with argument {value}"), "/path%20with%20argument%20{value}"); + + // few examples from Slim documentation + Assert.assertEquals(codegen.encodePath("/users[/{id}]"), "/users[/{id}]"); + Assert.assertEquals(codegen.encodePath("/news[/{year}[/{month}]]"), "/news[/{year}[/{month}]]"); + Assert.assertEquals(codegen.encodePath("/news[/{params:.*}]"), "/news[/{params:.*}]"); + Assert.assertEquals(codegen.encodePath("/users/{id:[0-9]+}"), "/users/{id:[0-9]+}"); + + // from FastRoute\RouteParser\Std.php + Assert.assertEquals(codegen.encodePath("/user/{name}[/{id:[0-9]+}]"), "/user/{name}[/{id:[0-9]+}]"); + Assert.assertEquals(codegen.encodePath("/fixedRoutePart/{varName}[/moreFixed/{varName2:\\d+}]"), "/fixedRoutePart/{varName}[/moreFixed/{varName2:\\d+}]"); + } +} diff --git a/samples/server/petstore-security-test/php-slim/lib/SlimRouter.php b/samples/server/petstore-security-test/php-slim/lib/SlimRouter.php index f57b96bed30..df080b40c38 100644 --- a/samples/server/petstore-security-test/php-slim/lib/SlimRouter.php +++ b/samples/server/petstore-security-test/php-slim/lib/SlimRouter.php @@ -53,7 +53,7 @@ class SlimRouter private $operations = [ [ 'httpMethod' => 'PUT', - 'basePathWithoutHost' => '/ ' \" =end -- \\r\\n \\n \\r/v2 *_/ ' \" =end -- \\r\\n \\n \\r', + 'basePathWithoutHost' => '/%20%27%20%22%20%3Dend%20--%20%5C%5Cr%5C%5Cn%20%5C%5Cn%20%5C%5Cr/v2%20*_/%20%27%20%22%20%3Dend%20--%20%5C%5Cr%5C%5Cn%20%5C%5Cn%20%5C%5Cr', 'path' => '/fake', 'apiPackage' => 'OpenAPIServer\Api', 'classname' => 'AbstractFakeApi',