Skip to content

Commit e740f50

Browse files
82marbagdavid-perez
authored andcommitted
Lazy initialize mime accept header (#2629)
## Description Do not parse and initialize the mime, known at compile time, on every request. See #2607 (comment) ## Checklist <!--- If a checkbox below is not applicable, then please DELETE it rather than leaving it unchecked --> - [ ] I have updated `CHANGELOG.next.toml` if I made changes to the smithy-rs codegen or runtime crates - [ ] I have updated `CHANGELOG.next.toml` if I made changes to the AWS SDK, generated SDK code, or SDK runtime crates ---- _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._ --------- Signed-off-by: Daniele Ahmed <[email protected]>
1 parent 953ed92 commit e740f50

File tree

2 files changed

+50
-13
lines changed

2 files changed

+50
-13
lines changed

Diff for: codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpBoundProtocolGenerator.kt

+21-1
Original file line numberDiff line numberDiff line change
@@ -178,18 +178,36 @@ class ServerHttpBoundProtocolTraitImplGenerator(
178178
outputSymbol: Symbol,
179179
operationShape: OperationShape,
180180
) {
181+
val operationName = symbolProvider.toSymbol(operationShape).name
182+
val staticContentType = "CONTENT_TYPE_${operationName.uppercase()}"
181183
val verifyAcceptHeader = writable {
182184
httpBindingResolver.responseContentType(operationShape)?.also { contentType ->
183185
rustTemplate(
184186
"""
185-
if !#{SmithyHttpServer}::protocols::accept_header_classifier(request.headers(), ${contentType.dq()}) {
187+
if !#{SmithyHttpServer}::protocols::accept_header_classifier(request.headers(), &$staticContentType) {
186188
return Err(#{RequestRejection}::NotAcceptable);
187189
}
188190
""",
189191
*codegenScope,
190192
)
191193
}
192194
}
195+
val verifyAcceptHeaderStaticContentTypeInit = writable {
196+
httpBindingResolver.responseContentType(operationShape)?.also { contentType ->
197+
val init = when (contentType) {
198+
"application/json" -> "const $staticContentType: #{Mime}::Mime = #{Mime}::APPLICATION_JSON;"
199+
"application/octet-stream" -> "const $staticContentType: #{Mime}::Mime = #{Mime}::APPLICATION_OCTET_STREAM;"
200+
"application/x-www-form-urlencoded" -> "const $staticContentType: #{Mime}::Mime = #{Mime}::APPLICATION_WWW_FORM_URLENCODED;"
201+
else ->
202+
"""
203+
static $staticContentType: #{OnceCell}::sync::Lazy<#{Mime}::Mime> = #{OnceCell}::sync::Lazy::new(|| {
204+
${contentType.dq()}.parse::<#{Mime}::Mime>().expect("BUG: MIME parsing failed, content_type is not valid")
205+
});
206+
"""
207+
}
208+
rustTemplate(init, *codegenScope)
209+
}
210+
}
193211
val verifyRequestContentTypeHeader = writable {
194212
operationShape
195213
.inputShape(model)
@@ -215,6 +233,7 @@ class ServerHttpBoundProtocolTraitImplGenerator(
215233
// TODO(https://github.com/awslabs/smithy-rs/issues/2238): Remove the `Pin<Box<dyn Future>>` and replace with thin wrapper around `Collect`.
216234
rustTemplate(
217235
"""
236+
#{verifyAcceptHeaderStaticContentTypeInit:W}
218237
#{PinProjectLite}::pin_project! {
219238
/// A [`Future`](std::future::Future) aggregating the body bytes of a [`Request`] and constructing the
220239
/// [`${inputSymbol.name}`](#{I}) using modelled bindings.
@@ -267,6 +286,7 @@ class ServerHttpBoundProtocolTraitImplGenerator(
267286
"Marker" to protocol.markerStruct(),
268287
"parse_request" to serverParseRequest(operationShape),
269288
"verifyAcceptHeader" to verifyAcceptHeader,
289+
"verifyAcceptHeaderStaticContentTypeInit" to verifyAcceptHeaderStaticContentTypeInit,
270290
"verifyRequestContentTypeHeader" to verifyRequestContentTypeHeader,
271291
)
272292

Diff for: rust-runtime/aws-smithy-http-server/src/protocols.rs

+29-12
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,10 @@ pub fn content_type_header_classifier(
6666
Ok(())
6767
}
6868

69-
pub fn accept_header_classifier(headers: &HeaderMap, content_type: &'static str) -> bool {
69+
pub fn accept_header_classifier(headers: &HeaderMap, content_type: &mime::Mime) -> bool {
7070
if !headers.contains_key(http::header::ACCEPT) {
7171
return true;
7272
}
73-
// Must be of the form: type/subtype
74-
let content_type = content_type
75-
.parse::<mime::Mime>()
76-
.expect("BUG: MIME parsing failed, content_type is not valid");
7773
headers
7874
.get_all(http::header::ACCEPT)
7975
.into_iter()
@@ -195,41 +191,62 @@ mod tests {
195191
#[test]
196192
fn valid_accept_header_classifier_multiple_values() {
197193
let valid_request = req_accept("text/strings, application/json, invalid");
198-
assert!(accept_header_classifier(&valid_request, "application/json"));
194+
assert!(accept_header_classifier(
195+
&valid_request,
196+
&"application/json".parse().unwrap()
197+
));
199198
}
200199

201200
#[test]
202201
fn invalid_accept_header_classifier() {
203202
let invalid_request = req_accept("text/invalid, invalid, invalid/invalid");
204-
assert!(!accept_header_classifier(&invalid_request, "application/json"));
203+
assert!(!accept_header_classifier(
204+
&invalid_request,
205+
&"application/json".parse().unwrap()
206+
));
205207
}
206208

207209
#[test]
208210
fn valid_accept_header_classifier_star() {
209211
let valid_request = req_accept("application/*");
210-
assert!(accept_header_classifier(&valid_request, "application/json"));
212+
assert!(accept_header_classifier(
213+
&valid_request,
214+
&"application/json".parse().unwrap()
215+
));
211216
}
212217

213218
#[test]
214219
fn valid_accept_header_classifier_star_star() {
215220
let valid_request = req_accept("*/*");
216-
assert!(accept_header_classifier(&valid_request, "application/json"));
221+
assert!(accept_header_classifier(
222+
&valid_request,
223+
&"application/json".parse().unwrap()
224+
));
217225
}
218226

219227
#[test]
220228
fn valid_empty_accept_header_classifier() {
221-
assert!(accept_header_classifier(&HeaderMap::new(), "application/json"));
229+
assert!(accept_header_classifier(
230+
&HeaderMap::new(),
231+
&"application/json".parse().unwrap()
232+
));
222233
}
223234

224235
#[test]
225236
fn valid_accept_header_classifier_with_params() {
226237
let valid_request = req_accept("application/json; q=30, */*");
227-
assert!(accept_header_classifier(&valid_request, "application/json"));
238+
assert!(accept_header_classifier(
239+
&valid_request,
240+
&"application/json".parse().unwrap()
241+
));
228242
}
229243

230244
#[test]
231245
fn valid_accept_header_classifier() {
232246
let valid_request = req_accept("application/json");
233-
assert!(accept_header_classifier(&valid_request, "application/json"));
247+
assert!(accept_header_classifier(
248+
&valid_request,
249+
&"application/json".parse().unwrap()
250+
));
234251
}
235252
}

0 commit comments

Comments
 (0)