Skip to content

Commit dd58147

Browse files
committed
feat: Support selective ssl/tls backend in rust-server to avoid always requiring openssl
1 parent acb80ba commit dd58147

27 files changed

Lines changed: 589 additions & 94 deletions

File tree

.github/workflows/samples-rust-server.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ jobs:
6464
if cargo read-manifest | grep -q '"validate"'; then
6565
cargo build --features validate --all-targets
6666
fi
67+
# Client without TLS (HTTP-only)
68+
if cargo read-manifest | grep -q '"client-tls"'; then
69+
cargo build --no-default-features --features=client --lib
70+
# Client with selective TLS backend
71+
cargo build --no-default-features --features=client,client-tls --lib
72+
cargo build --no-default-features --features=server --lib
73+
fi
6774
cargo fmt
6875
cargo test
6976
cargo clippy

modules/openapi-generator/src/main/resources/rust-server/Cargo.mustache

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ homepage = "{{.}}"
3232
{{/homePageUrl}}
3333

3434
[features]
35-
default = ["client", "server"]
35+
default = ["client", "server", "client-tls", "client-openssl"]
3636
client = [
3737
{{#apiUsesMultipartFormData}}
3838
"multipart", "multipart/client", "swagger/multipart_form",
@@ -47,7 +47,19 @@ client = [
4747
"serde_ignored", "percent-encoding", {{^apiUsesByteArray}}"lazy_static", "regex",{{/apiUsesByteArray}}
4848
{{/hasCallbacks}}
4949
{{! Anything added to the list below, should probably be added to the callbacks list below }}
50-
"hyper", "percent-encoding", "hyper-util/http1", "hyper-util/http2", "hyper-openssl", "hyper-tls", "native-tls", "openssl", "url"
50+
"hyper", "percent-encoding", "hyper-util/http1", "hyper-util/http2", "url"
51+
]
52+
# TLS support using native-tls (macOS/Windows/iOS) or hyper-tls
53+
client-tls = [
54+
"client",
55+
"hyper-tls", "native-tls",
56+
"swagger/tls"
57+
]
58+
# TLS support using OpenSSL (Linux and other platforms)
59+
client-openssl = [
60+
"client",
61+
"hyper-openssl", "openssl",
62+
"swagger/tls"
5163
]
5264
server = [
5365
{{#apiUsesMultipartFormData}}
@@ -57,7 +69,7 @@ server = [
5769
"mime_multipart", "swagger/multipart_related",
5870
{{/apiUsesMultipartRelated}}
5971
{{#hasCallbacks}}
60-
"native-tls", "hyper-openssl", "hyper-tls", "openssl",
72+
"client-tls",
6173
{{/hasCallbacks}}
6274
{{! Anything added to the list below, should probably be added to the callbacks list above }}
6375
"serde_ignored", "hyper", "percent-encoding", "url",
@@ -87,7 +99,7 @@ openssl = { version = "0.10", optional = true }
8799
async-trait = "0.1.88"
88100
chrono = { version = "0.4", features = ["serde"] }
89101
futures = "0.3"
90-
swagger = { version = "7.0.0", features = ["serdejson", "server", "client", "tls"] }
102+
swagger = { version = "7.0.0", features = ["serdejson", "server", "client"] }
91103
headers = "0.4.0"
92104
log = "0.4.27"
93105

modules/openapi-generator/src/main/resources/rust-server/README.mustache

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,12 @@ The generated library has a few optional features that can be activated through
126126
* `client`
127127
* This defaults to enabled and creates the basic skeleton of a client implementation based on hyper
128128
* The constructed client implements the API trait by making remote API call.
129+
* `client-tls`
130+
* This defaults to enabled and provides HTTPS support using native-tls (macOS/Windows/iOS).
131+
* Enable this feature for TLS support on Apple and Windows platforms.
132+
* `client-openssl`
133+
* This defaults to enabled and provides HTTPS support using OpenSSL (Linux and other platforms).
134+
* Enable this feature for TLS support on Linux and other Unix-like platforms.
129135
* `conversions`
130136
* This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types.
131137
* `cli`
@@ -134,6 +140,22 @@ The generated library has a few optional features that can be activated through
134140
* This defaults to disabled and allows JSON Schema validation of received data using `MakeService::set_validation` or `Service::set_validation`.
135141
* Note, enabling validation will have a performance penalty, especially if the API heavily uses regex based checks.
136142

143+
### Minimal dependencies (no TLS)
144+
145+
If you only need HTTP support and want to minimize dependencies (e.g., to avoid OpenSSL build requirements), you can disable the default TLS features:
146+
147+
```toml
148+
[dependencies]
149+
{{{packageName}}} = { version = "{{{packageVersion}}}", default-features = false, features = ["server"] }
150+
```
151+
152+
Or for client-only without TLS:
153+
154+
```toml
155+
[dependencies]
156+
{{{packageName}}} = { version = "{{{packageVersion}}}", default-features = false, features = ["client"] }
157+
```
158+
137159
See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`.
138160

139161
## Documentation for API Endpoints

modules/openapi-generator/src/main/resources/rust-server/client-mod.mustache

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ impl<Connector, C> Client<
121121
#[derive(Debug, Clone)]
122122
pub enum HyperClient {
123123
Http(hyper_util::client::legacy::Client<hyper_util::client::legacy::connect::HttpConnector, BoxBody<Bytes, Infallible>>),
124+
#[cfg(any(
125+
all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")),
126+
all(feature = "client-openssl", not(any(target_os = "macos", target_os = "windows", target_os = "ios")))
127+
))]
124128
Https(hyper_util::client::legacy::Client<HttpsConnector, BoxBody<Bytes, Infallible>>),
125129
}
126130
@@ -132,7 +136,11 @@ impl Service<Request<BoxBody<Bytes, Infallible>>> for HyperClient {
132136
fn call(&self, req: Request<BoxBody<Bytes, Infallible>>) -> Self::Future {
133137
match self {
134138
HyperClient::Http(client) => client.request(req),
135-
HyperClient::Https(client) => client.request(req)
139+
#[cfg(any(
140+
all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")),
141+
all(feature = "client-openssl", not(any(target_os = "macos", target_os = "windows", target_os = "ios")))
142+
))]
143+
HyperClient::Https(client) => client.request(req),
136144
}
137145
}
138146
}
@@ -158,12 +166,23 @@ impl<C> Client<DropContextService<HyperClient, C>, C> where
158166
"http" => {
159167
HyperClient::Http(hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector.build()))
160168
},
169+
#[cfg(any(
170+
all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")),
171+
all(feature = "client-openssl", not(any(target_os = "macos", target_os = "windows", target_os = "ios")))
172+
))]
161173
"https" => {
162174
let connector = connector.https()
163175
.build()
164176
.map_err(ClientInitError::SslError)?;
165177
HyperClient::Https(hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector))
166178
},
179+
#[cfg(not(any(
180+
all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")),
181+
all(feature = "client-openssl", not(any(target_os = "macos", target_os = "windows", target_os = "ios")))
182+
)))]
183+
"https" => {
184+
return Err(ClientInitError::TlsNotEnabled);
185+
},
167186
_ => {
168187
return Err(ClientInitError::InvalidScheme);
169188
}
@@ -206,12 +225,16 @@ impl<C> Client<
206225
}
207226
}
208227

209-
#[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))]
228+
#[cfg(all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")))]
210229
type HttpsConnector = hyper_tls::HttpsConnector<hyper_util::client::legacy::connect::HttpConnector>;
211230

212-
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
231+
#[cfg(all(feature = "client-openssl", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))]
213232
type HttpsConnector = hyper_openssl::client::legacy::HttpsConnector<hyper_util::client::legacy::connect::HttpConnector>;
214233

234+
#[cfg(any(
235+
all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")),
236+
all(feature = "client-openssl", not(any(target_os = "macos", target_os = "windows", target_os = "ios")))
237+
))]
215238
impl<C> Client<
216239
DropContextService<
217240
hyper_util::service::TowerToHyperService<
@@ -244,7 +267,7 @@ impl<C> Client<
244267
/// # Arguments
245268
/// * `base_path` - base path of the client API, i.e. "<http://www.my-api-implementation.com>"
246269
/// * `ca_certificate` - Path to CA certificate used to authenticate the server
247-
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
270+
#[cfg(all(feature = "client-openssl", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))]
248271
pub fn try_new_https_pinned<CA>(
249272
base_path: &str,
250273
ca_certificate: CA,
@@ -267,7 +290,7 @@ impl<C> Client<
267290
/// * `ca_certificate` - Path to CA certificate used to authenticate the server
268291
/// * `client_key` - Path to the client private key
269292
/// * `client_certificate` - Path to the client's public certificate associated with the private key
270-
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
293+
#[cfg(all(feature = "client-openssl", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))]
271294
pub fn try_new_https_mutual<CA, K, D>(
272295
base_path: &str,
273296
ca_certificate: CA,
@@ -325,12 +348,15 @@ pub enum ClientInitError {
325348
/// Missing Hostname
326349
MissingHost,
327350
351+
/// HTTPS requested but TLS features not enabled
352+
TlsNotEnabled,
353+
328354
/// SSL Connection Error
329-
#[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))]
355+
#[cfg(all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")))]
330356
SslError(native_tls::Error),
331357
332358
/// SSL Connection Error
333-
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
359+
#[cfg(all(feature = "client-openssl", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))]
334360
SslError(openssl::error::ErrorStack),
335361
}
336362

modules/openapi-generator/src/main/resources/rust-server/server-callbacks.mustache

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,25 +97,29 @@ impl<C> Client<DropContextService<hyper_util::service::TowerToHyperService<hyper
9797
}
9898
}
9999

100-
#[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))]
100+
#[cfg(all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")))]
101101
type HttpsConnector = hyper_tls::HttpsConnector<hyper_util::client::legacy::connect::HttpConnector>;
102102

103-
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
103+
#[cfg(all(feature = "client-openssl", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))]
104104
type HttpsConnector = hyper_openssl::client::legacy::HttpsConnector<hyper_util::client::legacy::connect::HttpConnector>;
105105

106+
#[cfg(any(
107+
all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")),
108+
all(feature = "client-openssl", not(any(target_os = "macos", target_os = "windows", target_os = "ios")))
109+
))]
106110
impl<C> Client<DropContextService<hyper_util::service::TowerToHyperService<hyper_util::client::legacy::Client<HttpsConnector, BoxBody<Bytes, Infallible>>>, C>, C> where
107111
C: Clone + Send + Sync + 'static
108112
{
109113
/// Create a client with a TLS connection to the server.
110-
#[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))]
114+
#[cfg(all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")))]
111115
pub fn new_https() -> Result<Self, native_tls::Error>
112116
{
113117
let https_connector = Connector::builder().https().build()?;
114118
Ok(Self::new_with_connector(https_connector))
115119
}
116120

117121
/// Create a client with a TLS connection to the server.
118-
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
122+
#[cfg(all(feature = "client-openssl", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))]
119123
pub fn new_https() -> Result<Self, openssl::error::ErrorStack>
120124
{
121125
let https_connector = Connector::builder().https().build()?;
@@ -126,7 +130,7 @@ impl<C> Client<DropContextService<hyper_util::service::TowerToHyperService<hyper
126130
///
127131
/// # Arguments
128132
/// * `ca_certificate` - Path to CA certificate used to authenticate the server
129-
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
133+
#[cfg(all(feature = "client-openssl", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))]
130134
pub fn new_https_pinned<CA>(
131135
ca_certificate: CA,
132136
) -> Result<Self, openssl::error::ErrorStack> where
@@ -145,7 +149,7 @@ impl<C> Client<DropContextService<hyper_util::service::TowerToHyperService<hyper
145149
/// * `ca_certificate` - Path to CA certificate used to authenticate the server
146150
/// * `client_key` - Path to the client private key
147151
/// * `client_certificate` - Path to the client's public certificate associated with the private key
148-
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
152+
#[cfg(all(feature = "client-openssl", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))]
149153
pub fn new_https_mutual<CA, K, D>(
150154
ca_certificate: CA,
151155
client_key: K,

samples/server/petstore/rust-server/output/multipart-v3/Cargo.toml

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,23 @@ license = "Unlicense"
88
edition = "2018"
99

1010
[features]
11-
default = ["client", "server"]
11+
default = ["client", "server", "client-tls", "client-openssl"]
1212
client = [
1313
"multipart", "multipart/client", "swagger/multipart_form",
1414
"mime_multipart", "swagger/multipart_related",
15-
"hyper", "percent-encoding", "hyper-util/http1", "hyper-util/http2", "hyper-openssl", "hyper-tls", "native-tls", "openssl", "url"
15+
"hyper", "percent-encoding", "hyper-util/http1", "hyper-util/http2", "url"
16+
]
17+
# TLS support using native-tls (macOS/Windows/iOS) or hyper-tls
18+
client-tls = [
19+
"client",
20+
"hyper-tls", "native-tls",
21+
"swagger/tls"
22+
]
23+
# TLS support using OpenSSL (Linux and other platforms)
24+
client-openssl = [
25+
"client",
26+
"hyper-openssl", "openssl",
27+
"swagger/tls"
1628
]
1729
server = [
1830
"multipart", "multipart/server", "swagger/multipart_form",
@@ -41,7 +53,7 @@ openssl = { version = "0.10", optional = true }
4153
async-trait = "0.1.88"
4254
chrono = { version = "0.4", features = ["serde"] }
4355
futures = "0.3"
44-
swagger = { version = "7.0.0", features = ["serdejson", "server", "client", "tls"] }
56+
swagger = { version = "7.0.0", features = ["serdejson", "server", "client"] }
4557
headers = "0.4.0"
4658
log = "0.4.27"
4759

samples/server/petstore/rust-server/output/multipart-v3/README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ The generated library has a few optional features that can be activated through
111111
* `client`
112112
* This defaults to enabled and creates the basic skeleton of a client implementation based on hyper
113113
* The constructed client implements the API trait by making remote API call.
114+
* `client-tls`
115+
* This defaults to enabled and provides HTTPS support using native-tls (macOS/Windows/iOS).
116+
* Enable this feature for TLS support on Apple and Windows platforms.
117+
* `client-openssl`
118+
* This defaults to enabled and provides HTTPS support using OpenSSL (Linux and other platforms).
119+
* Enable this feature for TLS support on Linux and other Unix-like platforms.
114120
* `conversions`
115121
* This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types.
116122
* `cli`
@@ -119,6 +125,22 @@ The generated library has a few optional features that can be activated through
119125
* This defaults to disabled and allows JSON Schema validation of received data using `MakeService::set_validation` or `Service::set_validation`.
120126
* Note, enabling validation will have a performance penalty, especially if the API heavily uses regex based checks.
121127

128+
### Minimal dependencies (no TLS)
129+
130+
If you only need HTTP support and want to minimize dependencies (e.g., to avoid OpenSSL build requirements), you can disable the default TLS features:
131+
132+
```toml
133+
[dependencies]
134+
multipart-v3 = { version = "1.0.7", default-features = false, features = ["server"] }
135+
```
136+
137+
Or for client-only without TLS:
138+
139+
```toml
140+
[dependencies]
141+
multipart-v3 = { version = "1.0.7", default-features = false, features = ["client"] }
142+
```
143+
122144
See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`.
123145

124146
## Documentation for API Endpoints

0 commit comments

Comments
 (0)