Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ namespace {{packageName}}.Client
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("{{httpUserAgent}}{{^httpUserAgent}}OpenAPI-Generator/{{packageVersion}}/csharp{{/httpUserAgent}}");
UserAgent = "{{httpUserAgent}}{{^httpUserAgent}}OpenAPI-Generator/{{packageVersion}}/csharp{{/httpUserAgent}}";
BasePath = "{{{basePath}}}";
DefaultHeaders = new {{^net35}}Concurrent{{/net35}}Dictionary<string, string>();
ApiKey = new {{^net35}}Concurrent{{/net35}}Dictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ namespace {{packageName}}.Client
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("{{httpUserAgent}}{{^httpUserAgent}}OpenAPI-Generator/{{packageVersion}}/csharp{{/httpUserAgent}}");
UserAgent = "{{httpUserAgent}}{{^httpUserAgent}}OpenAPI-Generator/{{packageVersion}}/csharp{{/httpUserAgent}}";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Removing WebUtility.UrlEncode also removed the escaping that kept user-supplied httpUserAgent values inside a valid C# string literal. A configured UA containing a double quote or backslash (previously encoded to %22/%5C) now emits a malformed literal such as UserAgent = "my "client"";, which fails to compile the generated SDK. Consider escaping \ and " in httpUserAgent (e.g., at the codegen level or via a template helper) before inserting it into the literal, since this value is user-controlled config.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/resources/csharp/Configuration.v790.mustache, line 129:

<comment>Removing WebUtility.UrlEncode also removed the escaping that kept user-supplied httpUserAgent values inside a valid C# string literal. A configured UA containing a double quote or backslash (previously encoded to %22/%5C) now emits a malformed literal such as `UserAgent = "my "client"";`, which fails to compile the generated SDK. Consider escaping `\` and `"` in httpUserAgent (e.g., at the codegen level or via a template helper) before inserting it into the literal, since this value is user-controlled config.</comment>

<file context>
@@ -126,7 +126,7 @@ namespace {{packageName}}.Client
         {
             Proxy = null;
-            UserAgent = WebUtility.UrlEncode("{{httpUserAgent}}{{^httpUserAgent}}OpenAPI-Generator/{{packageVersion}}/csharp{{/httpUserAgent}}");
+            UserAgent = "{{httpUserAgent}}{{^httpUserAgent}}OpenAPI-Generator/{{packageVersion}}/csharp{{/httpUserAgent}}";
             BasePath = "{{{basePath}}}";
             DefaultHeaders = new {{^net35}}Concurrent{{/net35}}Dictionary<string, string>();
</file context>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked this against both jars, and the escaping the UrlEncode call is credited with never existed at generation time.

WebUtility.UrlEncode runs at runtime, on a string literal that has already been emitted. The {{httpUserAgent}} substitution happens inside the quotes either way, so a value carrying " or \ lands in the literal identically before and after this change. Same spec, same generator, --library restsharp, httpUserAgent=my "client"\back:

master:

UserAgent = WebUtility.UrlEncode("my &quot;client&quot;\back");

this branch:

UserAgent = "my &quot;client&quot;\back";

Byte-identical literal; the wrapper is the whole delta.

Note the &quot;: mustache escapes the substitution, so a double quote never reaches the generated source as a quote in the first place and the literal stays well-formed on both sides. \b happens to be a valid C# escape so both of these compile — but a value ending in a backslash, or carrying an invalid escape such as \z, is malformed on master exactly as it is here. That makes it a pre-existing gap in how httpUserAgent is interpolated, shared with the generators that paste the same property into their own string literals (go/configuration.mustache, Java/ApiClient.mustache, php/Configuration.mustache, python/api_client.mustache, ...), rather than something this PR introduces.

Happy to look at escaping it properly at the codegen level as a separate cross-generator change if that is wanted — it does not belong to a fix that only removes a runtime call.

BasePath = "{{{basePath}}}";
DefaultHeaders = new {{^net35}}Concurrent{{/net35}}Dictionary<string, string>();
ApiKey = new {{^net35}}Concurrent{{/net35}}Dictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,35 @@ public void testHandleConstantParams() throws IOException {
"localVarRequestOptions.HeaderParameters.Add(\"X-CUSTOM_CONSTANT_HEADER\", Org.OpenAPITools.Client.ClientUtils.ParameterToString(\"CONSTANT_VALUE\"));");
}

@Test
public void testUserAgentIsNotUrlEncoded() throws IOException {
// both restsharp Configuration templates: the default one and the useIntForTimeout v7.9.0 fallback
for (boolean useIntForTimeout : new boolean[]{false, true}) {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
output.deleteOnExit();
final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/petstore.yaml");
final DefaultGenerator defaultGenerator = new DefaultGenerator();
final ClientOptInput clientOptInput = new ClientOptInput();
clientOptInput.openAPI(openAPI);
CSharpClientCodegen cSharpClientCodegen = new CSharpClientCodegen();
cSharpClientCodegen.setLibrary("restsharp");
cSharpClientCodegen.setOutputDir(output.getAbsolutePath());
cSharpClientCodegen.additionalProperties().put(CodegenConstants.HTTP_USER_AGENT, "my-client/1.2.3 (linux)");
cSharpClientCodegen.additionalProperties().put("useIntForTimeout", useIntForTimeout);
clientOptInput.config(cSharpClientCodegen);
defaultGenerator.opts(clientOptInput);

Map<String, File> files = defaultGenerator.generate().stream()
.collect(Collectors.toMap(File::getPath, Function.identity()));

File configuration = files
.get(Paths.get(output.getAbsolutePath(), "src", "Org.OpenAPITools", "Client", "Configuration.cs").toString());
assertNotNull(configuration);
assertFileContains(configuration.toPath(), "UserAgent = \"my-client/1.2.3 (linux)\";");
assertFileNotContains(configuration.toPath(), "UserAgent = WebUtility.UrlEncode(");
}
}

@Test
public void test31specAdditionalPropertiesOfOneOf() throws IOException {
// for https://github.com/OpenAPITools/openapi-generator/pull/18772
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://localhost:3000";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://localhost";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ internal class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://petstore.swagger.io/v2";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://petstore.swagger.io:80/v2";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ internal class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://petstore.swagger.io/v2";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://petstore.swagger.io:80/v2";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://petstore.swagger.io:80/v2";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://petstore.swagger.io/v2";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://localhost/v2";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://petstore.swagger.io/v2";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://petstore.swagger.io:80/v2";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://petstore.swagger.io:80/v2";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://petstore.swagger.io:80/v2";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://localhost";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://petstore.swagger.io:80/v2";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://localhost";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://petstore.swagger.io/v2";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://petstore.swagger.io:80/v2";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://petstore.swagger.io:80/v2";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://localhost/v2";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://petstore.swagger.io:80/v2";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://petstore.swagger.io:80/v2";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public class Configuration : IReadableConfiguration
public Configuration()
{
Proxy = null;
UserAgent = WebUtility.UrlEncode("OpenAPI-Generator/1.0.0/csharp");
UserAgent = "OpenAPI-Generator/1.0.0/csharp";
BasePath = "http://petstore.swagger.io:80/v2";
DefaultHeaders = new ConcurrentDictionary<string, string>();
ApiKey = new ConcurrentDictionary<string, string>();
Expand Down
Loading