Skip to content

Commit 6bd3d53

Browse files
authored
[PHP/Dart/Python] Correctly escape strings in single quotes (Fixes #17582) (#19529)
* [PHP/Dart/Python] Correctly escape strings in single quotes (Fixes #17582) * Move escapeTextInSingleQuotes method to DefaultCodegen, add docblock
1 parent 1bda458 commit 6bd3d53

File tree

22 files changed

+105
-67
lines changed

22 files changed

+105
-67
lines changed

modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,6 +1122,20 @@ public String escapeText(String input) {
11221122
.replace("\"", "\\\""));
11231123
}
11241124

1125+
/**
1126+
* This method escapes text to be used in a single quoted string
1127+
* @param input the input string
1128+
* @return the escaped string
1129+
*/
1130+
public String escapeTextInSingleQuotes(String input) {
1131+
if (input == null) {
1132+
return null;
1133+
}
1134+
1135+
return escapeText(input).replace("'", "\\'");
1136+
}
1137+
1138+
11251139
/**
11261140
* Escape characters while allowing new lines
11271141
*

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractDartCodegen.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -753,7 +753,7 @@ public String toEnumValue(String value, String datatype) {
753753
"int".equalsIgnoreCase(datatype)) {
754754
return value;
755755
} else {
756-
return "'" + escapeText(value) + "'";
756+
return "'" + escapeTextInSingleQuotes(value) + "'";
757757
}
758758
}
759759

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPhpCodegen.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -641,9 +641,10 @@ public void setParameterExampleValue(CodegenParameter p) {
641641

642642
if ("String".equalsIgnoreCase(type) || p.isString) {
643643
if (example == null) {
644-
example = "'" + p.paramName + "_example'";
644+
example = "'" + escapeTextInSingleQuotes(p.paramName) + "_example'";
645+
} else {
646+
example = escapeText(example);
645647
}
646-
example = escapeText(example);
647648
} else if ("Integer".equals(type) || "int".equals(type)) {
648649
if (example == null) {
649650
example = "56";
@@ -660,17 +661,17 @@ public void setParameterExampleValue(CodegenParameter p) {
660661
if (example == null) {
661662
example = "/path/to/file.txt";
662663
}
663-
example = "\"" + escapeText(example) + "\"";
664+
example = "'" + escapeTextInSingleQuotes(example) + "'";
664665
} else if ("\\Date".equalsIgnoreCase(type)) {
665666
if (example == null) {
666667
example = "2013-10-20";
667668
}
668-
example = "new \\DateTime(\"" + escapeText(example) + "\")";
669+
example = "new \\DateTime('" + escapeTextInSingleQuotes(example) + "')";
669670
} else if ("\\DateTime".equalsIgnoreCase(type)) {
670671
if (example == null) {
671672
example = "2013-10-20T19:20:30+01:00";
672673
}
673-
example = "new \\DateTime(\"" + escapeText(example) + "\")";
674+
example = "new \\DateTime('" + escapeTextInSingleQuotes(example) + "')";
674675
} else if ("object".equals(type)) {
675676
example = "new \\stdClass";
676677
} else if (!languageSpecificPrimitives.contains(type)) {
@@ -718,7 +719,7 @@ public String toEnumValue(String value, String datatype) {
718719
if ("int".equals(datatype) || "float".equals(datatype)) {
719720
return value;
720721
} else {
721-
return "\'" + escapeText(value) + "\'";
722+
return "'" + escapeTextInSingleQuotes(value) + "'";
722723
}
723724
}
724725

@@ -830,6 +831,16 @@ public String escapeText(String input) {
830831
return super.escapeText(input).trim();
831832
}
832833

834+
@Override
835+
public String escapeTextInSingleQuotes(String input) {
836+
if (input == null) {
837+
return input;
838+
}
839+
840+
// Unescape double quotes because PHP keeps the backslashes if a character does not need to be escaped
841+
return super.escapeTextInSingleQuotes(input).replace("\\\"", "\"");
842+
}
843+
833844
public void escapeMediaType(List<CodegenOperation> operationList) {
834845
for (CodegenOperation op : operationList) {
835846
if (!op.hasProduces) {

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPythonCodegen.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ private String toExampleValueRecursive(Schema schema, List<Schema> includedSchem
412412
// Enum case:
413413
example = schema.getEnum().get(0).toString();
414414
if (ModelUtils.isStringSchema(schema)) {
415-
example = "'" + escapeText(example) + "'";
415+
example = "'" + escapeTextInSingleQuotes(example) + "'";
416416
}
417417
if (null == example)
418418
LOGGER.warn("Empty enum. Cannot built an example!");
@@ -511,7 +511,7 @@ private String toExampleValueRecursive(Schema schema, List<Schema> includedSchem
511511
if (additional.getEnum() != null && !additional.getEnum().isEmpty()) {
512512
theKey = additional.getEnum().get(0).toString();
513513
if (ModelUtils.isStringSchema(additional)) {
514-
theKey = "'" + escapeText(theKey) + "'";
514+
theKey = "'" + escapeTextInSingleQuotes(theKey) + "'";
515515
}
516516
}
517517
example = "{\n" + indentationString + theKey + " : " + toExampleValueRecursive(additional, includedSchemas, indentation + 1) + "\n" + indentationString + "}";
@@ -577,7 +577,7 @@ private String toExampleValueRecursive(Schema schema, List<Schema> includedSchem
577577
}
578578

579579
if (ModelUtils.isStringSchema(schema)) {
580-
example = "'" + escapeText(example) + "'";
580+
example = "'" + escapeTextInSingleQuotes(example) + "'";
581581
}
582582

583583
return example;
@@ -603,7 +603,7 @@ public void setParameterExampleValue(CodegenParameter p) {
603603
if (example == null) {
604604
example = p.paramName + "_example";
605605
}
606-
example = "'" + escapeText(example) + "'";
606+
example = "'" + escapeTextInSingleQuotes(example) + "'";
607607
} else if ("Integer".equals(type) || "int".equals(type)) {
608608
if (example == null) {
609609
example = "56";
@@ -620,17 +620,17 @@ public void setParameterExampleValue(CodegenParameter p) {
620620
if (example == null) {
621621
example = "/path/to/file";
622622
}
623-
example = "'" + escapeText(example) + "'";
623+
example = "'" + escapeTextInSingleQuotes(example) + "'";
624624
} else if ("Date".equalsIgnoreCase(type)) {
625625
if (example == null) {
626626
example = "2013-10-20";
627627
}
628-
example = "'" + escapeText(example) + "'";
628+
example = "'" + escapeTextInSingleQuotes(example) + "'";
629629
} else if ("DateTime".equalsIgnoreCase(type)) {
630630
if (example == null) {
631631
example = "2013-10-20T19:20:30+01:00";
632632
}
633-
example = "'" + escapeText(example) + "'";
633+
example = "'" + escapeTextInSingleQuotes(example) + "'";
634634
} else if (!languageSpecificPrimitives.contains(type)) {
635635
// type is a model class, e.g. User
636636
example = this.packageName + "." + type + "()";
@@ -1419,7 +1419,7 @@ public String toEnumValue(String value, String datatype) {
14191419
if ("int".equals(datatype) || "float".equals(datatype)) {
14201420
return value;
14211421
} else {
1422-
return "\'" + escapeText(value) + "\'";
1422+
return "'" + escapeTextInSingleQuotes(value) + "'";
14231423
}
14241424
}
14251425

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PhpSymfonyServerCodegen.java

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -231,15 +231,6 @@ public String controllerFileFolder() {
231231
return (outputFolder + File.separator + toSrcPath(controllerPackage, srcBasePath));
232232
}
233233

234-
@Override
235-
public String escapeText(String input) {
236-
if (input != null) {
237-
// Trim the string to avoid leading and trailing spaces.
238-
return super.escapeText(input).trim();
239-
}
240-
return input;
241-
}
242-
243234
@Override
244235
public CodegenType getTag() {
245236
return CodegenType.SERVER;
@@ -577,15 +568,6 @@ public String toModelImport(String name) {
577568
}
578569
}
579570

580-
@Override
581-
public String toEnumValue(String value, String datatype) {
582-
if ("int".equals(datatype) || "float".equals(datatype)) {
583-
return value;
584-
} else {
585-
return "\"" + escapeText(value) + "\"";
586-
}
587-
}
588-
589571
/**
590572
* Return the regular expression/JSON schema pattern (http://json-schema.org/latest/json-schema-validation.html#anchor33)
591573
*

modules/openapi-generator/src/test/java/org/openapitools/codegen/dart/DartClientCodegenTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,15 @@ public void testKeywords() throws Exception {
8585
}
8686
}
8787

88+
89+
@Test(description = "Enum value with quotes (#17582)")
90+
public void testEnumPropertyWithQuotes() {
91+
final DartClientCodegen codegen = new DartClientCodegen();
92+
93+
Assert.assertEquals(codegen.toEnumValue("enum-value", "string"), "'enum-value'");
94+
Assert.assertEquals(codegen.toEnumValue("won't fix", "string"), "'won\\'t fix'");
95+
Assert.assertEquals(codegen.toEnumValue("\"", "string"), "'\\\"'");
96+
Assert.assertEquals(codegen.toEnumValue("1.0", "number"), "1.0");
97+
Assert.assertEquals(codegen.toEnumValue("1", "int"), "1");
98+
}
8899
}

modules/openapi-generator/src/test/java/org/openapitools/codegen/php/AbstractPhpCodegenTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,4 +176,13 @@ public void testEnumPropertyWithDefaultValue() {
176176
CodegenProperty cp1 = cm1.vars.get(0);
177177
Assert.assertEquals(cp1.getDefaultValue(), "'VALUE'");
178178
}
179+
180+
@Test(description = "Enum value with quotes (#17582)")
181+
public void testEnumPropertyWithQuotes() {
182+
Assert.assertEquals(codegen.toEnumValue("enum-value", "string"), "'enum-value'");
183+
Assert.assertEquals(codegen.toEnumValue("won't fix", "string"), "'won\\'t fix'");
184+
Assert.assertEquals(codegen.toEnumValue("\"", "string"), "'\"'");
185+
Assert.assertEquals(codegen.toEnumValue("1.0", "float"), "1.0");
186+
Assert.assertEquals(codegen.toEnumValue("1", "int"), "1");
187+
}
179188
}

modules/openapi-generator/src/test/java/org/openapitools/codegen/python/PythonClientCodegenTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,4 +530,15 @@ public void testHandleConstantParams() throws IOException {
530530
assertFileContains(apiFile.toPath(), "_header_params['X-CUSTOM_CONSTANT_HEADER'] = 'CONSTANT_VALUE'");
531531
assertFileContains(apiFile.toPath(), "_query_params.append(('CONSTANT_QUERY_STRING_KEY', 'CONSTANT_QUERY_STRING_VALUE'))");
532532
}
533+
534+
@Test(description = "Enum value with quotes (#17582)")
535+
public void testEnumPropertyWithQuotes() {
536+
final PythonClientCodegen codegen = new PythonClientCodegen();
537+
538+
Assert.assertEquals(codegen.toEnumValue("enum-value", "string"), "'enum-value'");
539+
Assert.assertEquals(codegen.toEnumValue("won't fix", "string"), "'won\\'t fix'");
540+
Assert.assertEquals(codegen.toEnumValue("\"", "string"), "'\\\"'");
541+
Assert.assertEquals(codegen.toEnumValue("1.0", "float"), "1.0");
542+
Assert.assertEquals(codegen.toEnumValue("1", "int"), "1");
543+
}
533544
}

samples/client/echo_api/php-nextgen-streaming/docs/Api/BodyApi.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ $apiInstance = new OpenAPI\Client\Api\BodyApi(
9292
// This is optional, `GuzzleHttp\Client` will be used as default.
9393
new GuzzleHttp\Client()
9494
);
95-
$body = "/path/to/file.txt"; // \Psr\Http\Message\StreamInterface
95+
$body = '/path/to/file.txt'; // \Psr\Http\Message\StreamInterface
9696

9797
try {
9898
$result = $apiInstance->testBodyApplicationOctetstreamBinary($body);
@@ -148,7 +148,7 @@ $apiInstance = new OpenAPI\Client\Api\BodyApi(
148148
// This is optional, `GuzzleHttp\Client` will be used as default.
149149
new GuzzleHttp\Client()
150150
);
151-
$files = array("/path/to/file.txt"); // \Psr\Http\Message\StreamInterface[]
151+
$files = array('/path/to/file.txt'); // \Psr\Http\Message\StreamInterface[]
152152

153153
try {
154154
$result = $apiInstance->testBodyMultipartFormdataArrayOfBinary($files);
@@ -204,7 +204,7 @@ $apiInstance = new OpenAPI\Client\Api\BodyApi(
204204
// This is optional, `GuzzleHttp\Client` will be used as default.
205205
new GuzzleHttp\Client()
206206
);
207-
$my_file = "/path/to/file.txt"; // \Psr\Http\Message\StreamInterface
207+
$my_file = '/path/to/file.txt'; // \Psr\Http\Message\StreamInterface
208208

209209
try {
210210
$result = $apiInstance->testBodyMultipartFormdataSingleBinary($my_file);

samples/client/echo_api/php-nextgen-streaming/docs/Api/QueryApi.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ $apiInstance = new OpenAPI\Client\Api\QueryApi(
9797
// This is optional, `GuzzleHttp\Client` will be used as default.
9898
new GuzzleHttp\Client()
9999
);
100-
$datetime_query = new \DateTime("2013-10-20T19:20:30+01:00"); // \DateTime
101-
$date_query = new \DateTime("2013-10-20T19:20:30+01:00"); // \DateTime
100+
$datetime_query = new \DateTime('2013-10-20T19:20:30+01:00'); // \DateTime
101+
$date_query = new \DateTime('2013-10-20T19:20:30+01:00'); // \DateTime
102102
$string_query = 'string_query_example'; // string
103103

104104
try {

0 commit comments

Comments
 (0)