From 1ebbf9b32e1650cedc7e1e64346cf5750a9189ac Mon Sep 17 00:00:00 2001 From: David Calavera Date: Sun, 3 Sep 2023 10:59:01 -0700 Subject: [PATCH 1/3] Fix streaming prelude serialization HTTP headers can be multi-value, but the current implementation ignores this fact and only serializes the first value for each header. This changes uses http-serde to serialize the prelude correctly. Signed-off-by: David Calavera --- lambda-runtime/Cargo.toml | 1 + lambda-runtime/src/streaming.rs | 68 +++++++++++++++++---------------- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/lambda-runtime/Cargo.toml b/lambda-runtime/Cargo.toml index 1de6f361..197265ab 100644 --- a/lambda-runtime/Cargo.toml +++ b/lambda-runtime/Cargo.toml @@ -42,3 +42,4 @@ tower = { version = "0.4", features = ["util"] } tokio-stream = "0.1.2" lambda_runtime_api_client = { version = "0.8", path = "../lambda-runtime-api-client" } serde_path_to_error = "0.1.11" +http-serde = "1.1.3" diff --git a/lambda-runtime/src/streaming.rs b/lambda-runtime/src/streaming.rs index e541f3d6..657e7bc8 100644 --- a/lambda-runtime/src/streaming.rs +++ b/lambda-runtime/src/streaming.rs @@ -5,13 +5,11 @@ use crate::{ use bytes::Bytes; use futures::FutureExt; use http::header::{CONTENT_TYPE, SET_COOKIE}; -use http::{Method, Request, Response, Uri}; +use http::{HeaderMap, Method, Request, Response, StatusCode, Uri}; use hyper::body::HttpBody; use hyper::{client::connect::Connection, Body}; use lambda_runtime_api_client::{build_request, Client}; -use serde::Deserialize; -use serde_json::json; -use std::collections::HashMap; +use serde::{Deserialize, Serialize}; use std::str::FromStr; use std::{ env, @@ -203,6 +201,16 @@ pub(crate) struct EventCompletionStreamingRequest<'a, B> { pub(crate) body: Response, } +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +struct MetadataPrelude { + #[serde(serialize_with = "http_serde::status_code::serialize")] + status_code: StatusCode, + #[serde(serialize_with = "http_serde::header_map::serialize")] + headers: HeaderMap, + cookies: Vec, +} + impl<'a, B> IntoRequest for EventCompletionStreamingRequest<'a, B> where B: HttpBody + Unpin + Send + 'static, @@ -216,45 +224,39 @@ where let (parts, mut body) = self.body.into_parts(); let mut builder = build_request().method(Method::POST).uri(uri); - let headers = builder.headers_mut().unwrap(); + let req_headers = builder.headers_mut().unwrap(); - headers.insert("Transfer-Encoding", "chunked".parse()?); - headers.insert("Lambda-Runtime-Function-Response-Mode", "streaming".parse()?); - headers.insert( + req_headers.insert("Transfer-Encoding", "chunked".parse()?); + req_headers.insert("Lambda-Runtime-Function-Response-Mode", "streaming".parse()?); + req_headers.insert( "Content-Type", "application/vnd.awslambda.http-integration-response".parse()?, ); - let (mut tx, rx) = Body::channel(); + let mut prelude_headers = parts.headers; + // default Content-Type + prelude_headers + .entry(CONTENT_TYPE) + .or_insert("application/octet-stream".parse().unwrap()); - tokio::spawn(async move { - let mut header_map = parts.headers; - // default Content-Type - header_map - .entry(CONTENT_TYPE) - .or_insert("application/octet-stream".parse().unwrap()); + let cookies = prelude_headers.get_all(SET_COOKIE); + let cookies = cookies + .iter() + .map(|c| String::from_utf8_lossy(c.as_bytes()).to_string()) + .collect::>(); + prelude_headers.remove(SET_COOKIE); - let cookies = header_map.get_all(SET_COOKIE); - let cookies = cookies - .iter() - .map(|c| String::from_utf8_lossy(c.as_bytes()).to_string()) - .collect::>(); + let metadata_prelude = serde_json::to_string(&MetadataPrelude { + status_code: parts.status, + headers: prelude_headers, + cookies, + })?; - let headers = header_map - .iter() - .filter(|(k, _)| *k != SET_COOKIE) - .map(|(k, v)| (k.as_str(), String::from_utf8_lossy(v.as_bytes()).to_string())) - .collect::>(); + trace!(?metadata_prelude); - let metadata_prelude = json!({ - "statusCode": parts.status.as_u16(), - "headers": headers, - "cookies": cookies, - }) - .to_string(); - - trace!("metadata_prelude: {}", metadata_prelude); + let (mut tx, rx) = Body::channel(); + tokio::spawn(async move { tx.send_data(metadata_prelude.into()).await.unwrap(); tx.send_data("\u{0}".repeat(8).into()).await.unwrap(); From 6fc03b62e9756cdd18f2aeafb5e7825acc582fa8 Mon Sep 17 00:00:00 2001 From: David Calavera Date: Mon, 4 Sep 2023 11:40:46 -0700 Subject: [PATCH 2/3] Update MSRV Some dependencies have dropped support for 1.62 already. Signed-off-by: David Calavera --- .github/workflows/build-events.yml | 2 +- .github/workflows/build-extension.yml | 2 +- .github/workflows/build-runtime.yml | 2 +- README.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-events.yml b/.github/workflows/build-events.yml index 3a56e597..4e5fb34d 100644 --- a/.github/workflows/build-events.yml +++ b/.github/workflows/build-events.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: toolchain: - - "1.62.0" # Current MSRV + - "1.64.0" # Current MSRV - stable env: RUST_BACKTRACE: 1 diff --git a/.github/workflows/build-extension.yml b/.github/workflows/build-extension.yml index 0905f289..7365bc64 100644 --- a/.github/workflows/build-extension.yml +++ b/.github/workflows/build-extension.yml @@ -18,7 +18,7 @@ jobs: strategy: matrix: toolchain: - - "1.62.0" # Current MSRV + - "1.64.0" # Current MSRV - stable env: RUST_BACKTRACE: 1 diff --git a/.github/workflows/build-runtime.yml b/.github/workflows/build-runtime.yml index 68913c95..9657a840 100644 --- a/.github/workflows/build-runtime.yml +++ b/.github/workflows/build-runtime.yml @@ -19,7 +19,7 @@ jobs: strategy: matrix: toolchain: - - "1.62.0" # Current MSRV + - "1.64.0" # Current MSRV - stable env: RUST_BACKTRACE: 1 diff --git a/README.md b/README.md index 12dbf523..5f6f899a 100644 --- a/README.md +++ b/README.md @@ -440,7 +440,7 @@ This will make your function compile much faster. ## Supported Rust Versions (MSRV) -The AWS Lambda Rust Runtime requires a minimum of Rust 1.62, and is not guaranteed to build on compiler versions earlier than that. +The AWS Lambda Rust Runtime requires a minimum of Rust 1.64, and is not guaranteed to build on compiler versions earlier than that. ## Security From 37721968b750933fbfacd2d621be5c6a9fdcfc90 Mon Sep 17 00:00:00 2001 From: David Calavera Date: Mon, 4 Sep 2023 12:13:04 -0700 Subject: [PATCH 3/3] Remove unwrap Signed-off-by: David Calavera --- lambda-runtime/src/streaming.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lambda-runtime/src/streaming.rs b/lambda-runtime/src/streaming.rs index 657e7bc8..5ea369ad 100644 --- a/lambda-runtime/src/streaming.rs +++ b/lambda-runtime/src/streaming.rs @@ -237,7 +237,7 @@ where // default Content-Type prelude_headers .entry(CONTENT_TYPE) - .or_insert("application/octet-stream".parse().unwrap()); + .or_insert("application/octet-stream".parse()?); let cookies = prelude_headers.get_all(SET_COOKIE); let cookies = cookies