Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add custom response header to force text encoding #533

Merged
merged 1 commit into from Oct 5, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
62 changes: 60 additions & 2 deletions lambda-http/src/response.rs
Expand Up @@ -23,6 +23,8 @@ use std::borrow::Cow;
use std::future::ready;
use std::{fmt, future::Future, pin::Pin};

const X_LAMBDA_HTTP_CONTENT_ENCODING: &str = "x-lambda-http-content-encoding";

/// Representation of Lambda response
#[doc(hidden)]
#[derive(Serialize, Debug)]
Expand Down Expand Up @@ -181,7 +183,7 @@ where
return convert_to_binary(self);
}

let content_type = if let Some(value) = headers.get(http::header::CONTENT_TYPE) {
let content_type = if let Some(value) = headers.get(CONTENT_TYPE) {
value.to_str().unwrap_or_default()
} else {
// Content-Type and Content-Encoding not set, passthrough as utf8 text
Expand All @@ -199,6 +201,12 @@ where
return convert_to_text(self, content_type);
}

if let Some(value) = headers.get(X_LAMBDA_HTTP_CONTENT_ENCODING) {
if value == "text" {
return convert_to_text(self, content_type);
}
}

Comment on lines +204 to +209
Copy link
Contributor

Choose a reason for hiding this comment

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

Once this header is set to 'text', the response will be treated as text response. If a web app returns both text and binary data, it has to set this header based on the type of data returned. This seems to put more work on the web app developers.

Choose a reason for hiding this comment

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

Would it be possible to use the lambda_http::Body to set this behind the scenes?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, you can directly use lambda_http::Body to indicate text or binary response. This is for generic http::Body.

convert_to_binary(self)
}
}
Expand Down Expand Up @@ -242,14 +250,16 @@ pub type BodyFuture = Pin<Box<dyn Future<Output = Body>>>;

#[cfg(test)]
mod tests {
use super::{Body, IntoResponse, LambdaResponse, RequestOrigin};
use super::{Body, IntoResponse, LambdaResponse, RequestOrigin, X_LAMBDA_HTTP_CONTENT_ENCODING};
use http::{
header::{CONTENT_ENCODING, CONTENT_TYPE},
Response,
};
use hyper::Body as HyperBody;
use serde_json::{self, json};

const SVG_LOGO: &str = include_str!("../tests/data/svg_logo.svg");

#[tokio::test]
async fn json_into_response() {
let response = json!({ "hello": "lambda"}).into_response().await;
Expand Down Expand Up @@ -388,4 +398,52 @@ mod tests {
json
)
}

#[tokio::test]
async fn content_type_xml_as_text() {
// Drive the implementation by using `hyper::Body` instead of
// of `aws_lambda_events::encodings::Body`
let response = Response::builder()
.header(CONTENT_TYPE, "image/svg+xml")
.body(HyperBody::from(SVG_LOGO.as_bytes()))
.expect("unable to build http::Response");
let response = response.into_response().await;

match response.body() {
Body::Text(body) => assert_eq!(SVG_LOGO, body),
_ => panic!("invalid body"),
}
assert_eq!(
response
.headers()
.get(CONTENT_TYPE)
.map(|h| h.to_str().expect("invalid header")),
Some("image/svg+xml")
)
}

#[tokio::test]
async fn content_type_custom_encoding_as_text() {
// Drive the implementation by using `hyper::Body` instead of
// of `aws_lambda_events::encodings::Body`
let response = Response::builder()
// this CONTENT-TYPE is not standard, and would yield a binary response
.header(CONTENT_TYPE, "image/svg")
.header(X_LAMBDA_HTTP_CONTENT_ENCODING, "text")
.body(HyperBody::from(SVG_LOGO.as_bytes()))
.expect("unable to build http::Response");
let response = response.into_response().await;

match response.body() {
Body::Text(body) => assert_eq!(SVG_LOGO, body),
_ => panic!("invalid body"),
}
assert_eq!(
response
.headers()
.get(CONTENT_TYPE)
.map(|h| h.to_str().expect("invalid header")),
Some("image/svg")
)
}
}
49 changes: 49 additions & 0 deletions lambda-http/tests/data/svg_logo.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.