Skip to content

Commit 78ea8af

Browse files
authored
[Rust] harden against name collisions while generate cleaner rust code, fix #20337 (#20396)
* prevent all name clashes by using a prefix for all parameters, this way they CANNOT clash with anything locally, as our hardcoded stuff in mustache files doesnt start with "p_" , when using the grouped option, we just use the params directly and dont unpack the variables at all, prevending furthur name clashes. * get rid of "local_var" prefix, now that we no longer clash with paramater names * fix a typo and remove the r# generated to the paramName when we create the identifier * java code formatting and added a fake-endpoint parameter test * update rust samples
1 parent 09530b4 commit 78ea8af

File tree

62 files changed

+3382
-4317
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+3382
-4317
lines changed

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

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ public abstract class AbstractRustCodegen extends DefaultCodegen implements Code
2121

2222
private final Logger LOGGER = LoggerFactory.getLogger(AbstractRustCodegen.class);
2323

24+
protected static final String VENDOR_EXTENSION_PARAM_IDENTIFIER = "x-rust-param-identifier";
25+
2426
protected List<String> charactersToAllow = Collections.singletonList("_");
2527
protected Set<String> keywordsThatDoNotSupportRawIdentifiers = new HashSet<>(
2628
Arrays.asList("super", "self", "Self", "extern", "crate"));

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

+22-1
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@
3939
import org.openapitools.codegen.CodegenModel;
4040
import org.openapitools.codegen.CodegenOperation;
4141
import org.openapitools.codegen.CodegenProperty;
42+
import org.openapitools.codegen.CodegenParameter;
4243
import org.openapitools.codegen.CodegenType;
4344
import org.openapitools.codegen.SupportingFile;
45+
import org.openapitools.codegen.VendorExtension;
4446
import org.openapitools.codegen.meta.features.ClientModificationFeature;
4547
import org.openapitools.codegen.meta.features.DocumentationFeature;
4648
import org.openapitools.codegen.meta.features.GlobalFeature;
@@ -602,6 +604,25 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
602604
}
603605
}
604606

607+
@Override
608+
public void postProcessParameter(CodegenParameter parameter) {
609+
super.postProcessParameter(parameter);
610+
// in order to avoid name conflicts, we map parameters inside the functions
611+
String inFunctionIdentifier = "";
612+
if (this.useSingleRequestParameter) {
613+
inFunctionIdentifier = "params." + parameter.paramName;
614+
} else {
615+
if (parameter.paramName.startsWith("r#")) {
616+
inFunctionIdentifier = "p_" + parameter.paramName.substring(2);
617+
} else {
618+
inFunctionIdentifier = "p_" + parameter.paramName;
619+
}
620+
}
621+
if (!parameter.vendorExtensions.containsKey(this.VENDOR_EXTENSION_PARAM_IDENTIFIER)) { // allow to overwrite this value
622+
parameter.vendorExtensions.put(this.VENDOR_EXTENSION_PARAM_IDENTIFIER, inFunctionIdentifier);
623+
}
624+
}
625+
605626
@Override
606627
public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<ModelMap> allModels) {
607628
OperationMap objectMap = objs.getOperations();
@@ -699,7 +720,7 @@ public String toDefaultValue(Schema p) {
699720
@Override
700721
protected ImmutableMap.Builder<String, Lambda> addMustacheLambdas() {
701722
return super.addMustacheLambdas()
702-
// Convert variable names to lifetime names.
723+
// Convert variable names to lifetime names.
703724
// Generally they are the same, but `#` is not valid in lifetime names.
704725
// Rust uses `r#` prefix for variables that are also keywords.
705726
.put("lifetimeName", new ReplaceAllLambda("^r#", "r_"));

modules/openapi-generator/src/main/resources/rust/reqwest/api.mustache

+100-106
Large diffs are not rendered by default.

modules/openapi-generator/src/test/resources/3_0/rust/petstore.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,11 @@ paths:
608608
description: To test parameter names in upper case
609609
schema:
610610
type: string
611+
- name: content
612+
in: query
613+
description: To test escaping of parameters in rust code works
614+
schema:
615+
type: string
611616
responses:
612617
'200':
613618
description: successful operation

samples/client/others/rust/reqwest-regression-16119/src/apis/default_api.rs

+13-17
Original file line numberDiff line numberDiff line change
@@ -24,30 +24,26 @@ pub enum ReproError {
2424

2525

2626
pub fn repro(configuration: &configuration::Configuration, ) -> Result<models::Parent, Error<ReproError>> {
27-
let local_var_configuration = configuration;
2827

29-
let local_var_client = &local_var_configuration.client;
28+
let uri_str = format!("{}/repro", configuration.base_path);
29+
let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
3030

31-
let local_var_uri_str = format!("{}/repro", local_var_configuration.base_path);
32-
let mut local_var_req_builder = local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
33-
34-
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
35-
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
31+
if let Some(ref user_agent) = configuration.user_agent {
32+
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
3633
}
3734

38-
let local_var_req = local_var_req_builder.build()?;
39-
let local_var_resp = local_var_client.execute(local_var_req)?;
35+
let req = req_builder.build()?;
36+
let resp = configuration.client.execute(req)?;
4037

41-
let local_var_status = local_var_resp.status();
38+
let status = resp.status();
4239

43-
if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
44-
let local_var_content = local_var_resp.text()?;
45-
serde_json::from_str(&local_var_content).map_err(Error::from)
40+
if !status.is_client_error() && !status.is_server_error() {
41+
let content = resp.text()?;
42+
serde_json::from_str(&content).map_err(Error::from)
4643
} else {
47-
let local_var_content = local_var_resp.text()?;
48-
let local_var_entity: Option<ReproError> = serde_json::from_str(&local_var_content).ok();
49-
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
50-
Err(Error::ResponseError(local_var_error))
44+
let content = resp.text()?;
45+
let entity: Option<ReproError> = serde_json::from_str(&content).ok();
46+
Err(Error::ResponseError(ResponseContent { status, content, entity }))
5147
}
5248
}
5349

samples/client/others/rust/reqwest/api-with-ref-param/src/apis/default_api.rs

+13-15
Original file line numberDiff line numberDiff line change
@@ -24,29 +24,27 @@ pub enum DemoColorGetError {
2424

2525

2626
pub async fn demo_color_get(configuration: &configuration::Configuration, color: models::Color) -> Result<(), Error<DemoColorGetError>> {
27-
let local_var_configuration = configuration;
27+
// add a prefix to parameters to efficiently prevent name collisions
28+
let p_color = color;
2829

29-
let local_var_client = &local_var_configuration.client;
30+
let uri_str = format!("{}/demo/{color}", configuration.base_path, color=p_color.to_string());
31+
let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
3032

31-
let local_var_uri_str = format!("{}/demo/{color}", local_var_configuration.base_path, color=color.to_string());
32-
let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
33-
34-
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
35-
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
33+
if let Some(ref user_agent) = configuration.user_agent {
34+
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
3635
}
3736

38-
let local_var_req = local_var_req_builder.build()?;
39-
let local_var_resp = local_var_client.execute(local_var_req).await?;
37+
let req = req_builder.build()?;
38+
let resp = configuration.client.execute(req).await?;
4039

41-
let local_var_status = local_var_resp.status();
40+
let status = resp.status();
4241

43-
if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
42+
if !status.is_client_error() && !status.is_server_error() {
4443
Ok(())
4544
} else {
46-
let local_var_content = local_var_resp.text().await?;
47-
let local_var_entity: Option<DemoColorGetError> = serde_json::from_str(&local_var_content).ok();
48-
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
49-
Err(Error::ResponseError(local_var_error))
45+
let content = resp.text().await?;
46+
let entity: Option<DemoColorGetError> = serde_json::from_str(&content).ok();
47+
Err(Error::ResponseError(ResponseContent { status, content, entity }))
5048
}
5149
}
5250

samples/client/others/rust/reqwest/composed-oneof/src/apis/default_api.rs

+27-33
Original file line numberDiff line numberDiff line change
@@ -31,58 +31,52 @@ pub enum GetStateError {
3131

3232

3333
pub fn create_state(configuration: &configuration::Configuration, create_state_request: models::CreateStateRequest) -> Result<(), Error<CreateStateError>> {
34-
let local_var_configuration = configuration;
34+
// add a prefix to parameters to efficiently prevent name collisions
35+
let p_create_state_request = create_state_request;
3536

36-
let local_var_client = &local_var_configuration.client;
37+
let uri_str = format!("{}/state", configuration.base_path);
38+
let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
3739

38-
let local_var_uri_str = format!("{}/state", local_var_configuration.base_path);
39-
let mut local_var_req_builder = local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
40-
41-
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
42-
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
40+
if let Some(ref user_agent) = configuration.user_agent {
41+
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
4342
}
44-
local_var_req_builder = local_var_req_builder.json(&create_state_request);
43+
req_builder = req_builder.json(&p_create_state_request);
4544

46-
let local_var_req = local_var_req_builder.build()?;
47-
let local_var_resp = local_var_client.execute(local_var_req)?;
45+
let req = req_builder.build()?;
46+
let resp = configuration.client.execute(req)?;
4847

49-
let local_var_status = local_var_resp.status();
48+
let status = resp.status();
5049

51-
if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
50+
if !status.is_client_error() && !status.is_server_error() {
5251
Ok(())
5352
} else {
54-
let local_var_content = local_var_resp.text()?;
55-
let local_var_entity: Option<CreateStateError> = serde_json::from_str(&local_var_content).ok();
56-
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
57-
Err(Error::ResponseError(local_var_error))
53+
let content = resp.text()?;
54+
let entity: Option<CreateStateError> = serde_json::from_str(&content).ok();
55+
Err(Error::ResponseError(ResponseContent { status, content, entity }))
5856
}
5957
}
6058

6159
pub fn get_state(configuration: &configuration::Configuration, ) -> Result<models::GetState200Response, Error<GetStateError>> {
62-
let local_var_configuration = configuration;
63-
64-
let local_var_client = &local_var_configuration.client;
6560

66-
let local_var_uri_str = format!("{}/state", local_var_configuration.base_path);
67-
let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
61+
let uri_str = format!("{}/state", configuration.base_path);
62+
let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
6863

69-
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
70-
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
64+
if let Some(ref user_agent) = configuration.user_agent {
65+
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
7166
}
7267

73-
let local_var_req = local_var_req_builder.build()?;
74-
let local_var_resp = local_var_client.execute(local_var_req)?;
68+
let req = req_builder.build()?;
69+
let resp = configuration.client.execute(req)?;
7570

76-
let local_var_status = local_var_resp.status();
71+
let status = resp.status();
7772

78-
if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
79-
let local_var_content = local_var_resp.text()?;
80-
serde_json::from_str(&local_var_content).map_err(Error::from)
73+
if !status.is_client_error() && !status.is_server_error() {
74+
let content = resp.text()?;
75+
serde_json::from_str(&content).map_err(Error::from)
8176
} else {
82-
let local_var_content = local_var_resp.text()?;
83-
let local_var_entity: Option<GetStateError> = serde_json::from_str(&local_var_content).ok();
84-
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
85-
Err(Error::ResponseError(local_var_error))
77+
let content = resp.text()?;
78+
let entity: Option<GetStateError> = serde_json::from_str(&content).ok();
79+
Err(Error::ResponseError(ResponseContent { status, content, entity }))
8680
}
8781
}
8882

samples/client/others/rust/reqwest/emptyObject/src/apis/default_api.rs

+13-17
Original file line numberDiff line numberDiff line change
@@ -24,30 +24,26 @@ pub enum EndpointGetError {
2424

2525

2626
pub fn endpoint_get(configuration: &configuration::Configuration, ) -> Result<models::EmptyObject, Error<EndpointGetError>> {
27-
let local_var_configuration = configuration;
2827

29-
let local_var_client = &local_var_configuration.client;
28+
let uri_str = format!("{}/endpoint", configuration.base_path);
29+
let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
3030

31-
let local_var_uri_str = format!("{}/endpoint", local_var_configuration.base_path);
32-
let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
33-
34-
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
35-
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
31+
if let Some(ref user_agent) = configuration.user_agent {
32+
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
3633
}
3734

38-
let local_var_req = local_var_req_builder.build()?;
39-
let local_var_resp = local_var_client.execute(local_var_req)?;
35+
let req = req_builder.build()?;
36+
let resp = configuration.client.execute(req)?;
4037

41-
let local_var_status = local_var_resp.status();
38+
let status = resp.status();
4239

43-
if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
44-
let local_var_content = local_var_resp.text()?;
45-
serde_json::from_str(&local_var_content).map_err(Error::from)
40+
if !status.is_client_error() && !status.is_server_error() {
41+
let content = resp.text()?;
42+
serde_json::from_str(&content).map_err(Error::from)
4643
} else {
47-
let local_var_content = local_var_resp.text()?;
48-
let local_var_entity: Option<EndpointGetError> = serde_json::from_str(&local_var_content).ok();
49-
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
50-
Err(Error::ResponseError(local_var_error))
44+
let content = resp.text()?;
45+
let entity: Option<EndpointGetError> = serde_json::from_str(&content).ok();
46+
Err(Error::ResponseError(ResponseContent { status, content, entity }))
5147
}
5248
}
5349

samples/client/others/rust/reqwest/oneOf-array-map/src/apis/default_api.rs

+27-33
Original file line numberDiff line numberDiff line change
@@ -31,58 +31,52 @@ pub enum TestError {
3131

3232

3333
pub fn root_get(configuration: &configuration::Configuration, ) -> Result<models::Fruit, Error<RootGetError>> {
34-
let local_var_configuration = configuration;
3534

36-
let local_var_client = &local_var_configuration.client;
35+
let uri_str = format!("{}/", configuration.base_path);
36+
let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
3737

38-
let local_var_uri_str = format!("{}/", local_var_configuration.base_path);
39-
let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
40-
41-
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
42-
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
38+
if let Some(ref user_agent) = configuration.user_agent {
39+
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
4340
}
4441

45-
let local_var_req = local_var_req_builder.build()?;
46-
let local_var_resp = local_var_client.execute(local_var_req)?;
42+
let req = req_builder.build()?;
43+
let resp = configuration.client.execute(req)?;
4744

48-
let local_var_status = local_var_resp.status();
45+
let status = resp.status();
4946

50-
if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
51-
let local_var_content = local_var_resp.text()?;
52-
serde_json::from_str(&local_var_content).map_err(Error::from)
47+
if !status.is_client_error() && !status.is_server_error() {
48+
let content = resp.text()?;
49+
serde_json::from_str(&content).map_err(Error::from)
5350
} else {
54-
let local_var_content = local_var_resp.text()?;
55-
let local_var_entity: Option<RootGetError> = serde_json::from_str(&local_var_content).ok();
56-
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
57-
Err(Error::ResponseError(local_var_error))
51+
let content = resp.text()?;
52+
let entity: Option<RootGetError> = serde_json::from_str(&content).ok();
53+
Err(Error::ResponseError(ResponseContent { status, content, entity }))
5854
}
5955
}
6056

6157
pub fn test(configuration: &configuration::Configuration, body: Option<serde_json::Value>) -> Result<(), Error<TestError>> {
62-
let local_var_configuration = configuration;
63-
64-
let local_var_client = &local_var_configuration.client;
58+
// add a prefix to parameters to efficiently prevent name collisions
59+
let p_body = body;
6560

66-
let local_var_uri_str = format!("{}/", local_var_configuration.base_path);
67-
let mut local_var_req_builder = local_var_client.request(reqwest::Method::PUT, local_var_uri_str.as_str());
61+
let uri_str = format!("{}/", configuration.base_path);
62+
let mut req_builder = configuration.client.request(reqwest::Method::PUT, &uri_str);
6863

69-
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
70-
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
64+
if let Some(ref user_agent) = configuration.user_agent {
65+
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
7166
}
72-
local_var_req_builder = local_var_req_builder.json(&body);
67+
req_builder = req_builder.json(&p_body);
7368

74-
let local_var_req = local_var_req_builder.build()?;
75-
let local_var_resp = local_var_client.execute(local_var_req)?;
69+
let req = req_builder.build()?;
70+
let resp = configuration.client.execute(req)?;
7671

77-
let local_var_status = local_var_resp.status();
72+
let status = resp.status();
7873

79-
if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
74+
if !status.is_client_error() && !status.is_server_error() {
8075
Ok(())
8176
} else {
82-
let local_var_content = local_var_resp.text()?;
83-
let local_var_entity: Option<TestError> = serde_json::from_str(&local_var_content).ok();
84-
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
85-
Err(Error::ResponseError(local_var_error))
77+
let content = resp.text()?;
78+
let entity: Option<TestError> = serde_json::from_str(&content).ok();
79+
Err(Error::ResponseError(ResponseContent { status, content, entity }))
8680
}
8781
}
8882

0 commit comments

Comments
 (0)