1- use crate :: { types:: ToStreamErrorTrailer , Diagnostic , Error , FunctionResponse , IntoFunctionResponse } ;
1+ use crate :: {
2+ constants:: LAMBDA_RUNTIME_INVOCATION_ID , types:: ToStreamErrorTrailer , Diagnostic , Error , FunctionResponse ,
3+ IntoFunctionResponse ,
4+ } ;
25use bytes:: Bytes ;
36use http:: { header:: CONTENT_TYPE , Method , Request , Uri } ;
47use lambda_runtime_api_client:: { body:: Body , build_request} ;
8891 E : Into < Error > + Send + Debug ,
8992{
9093 pub ( crate ) request_id : & ' a str ,
94+ pub ( crate ) invocation_id : Option < & ' a str > ,
9195 pub ( crate ) body : R ,
9296 pub ( crate ) _unused_b : PhantomData < B > ,
9397 pub ( crate ) _unused_s : PhantomData < S > ,
@@ -102,9 +106,14 @@ where
102106 E : Into < Error > + Send + Debug ,
103107{
104108 /// Initialize a new EventCompletionRequest
105- pub ( crate ) fn new ( request_id : & ' a str , body : R ) -> EventCompletionRequest < ' a , R , B , S , D , E > {
109+ pub ( crate ) fn new (
110+ request_id : & ' a str ,
111+ invocation_id : Option < & ' a str > ,
112+ body : R ,
113+ ) -> EventCompletionRequest < ' a , R , B , S , D , E > {
106114 EventCompletionRequest {
107115 request_id,
116+ invocation_id,
108117 body,
109118 _unused_b : PhantomData :: < B > ,
110119 _unused_s : PhantomData :: < S > ,
@@ -129,7 +138,15 @@ where
129138 let body = serde_json:: to_vec ( & body) ?;
130139 let body = Body :: from ( body) ;
131140
132- let req = build_request ( ) . method ( Method :: POST ) . uri ( uri) . body ( body) ?;
141+ let mut req = build_request ( )
142+ . method ( Method :: POST )
143+ . uri ( uri)
144+ . body ( body) ?;
145+
146+ if let Some ( id) = self . invocation_id {
147+ req. headers_mut ( ) . insert ( LAMBDA_RUNTIME_INVOCATION_ID , id. parse ( ) ?) ;
148+ }
149+
133150 Ok ( req)
134151 }
135152 FunctionResponse :: StreamingResponse ( mut response) => {
@@ -145,6 +162,11 @@ where
145162 // See the details in Lambda Developer Doc: https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html#runtimes-custom-response-streaming
146163 req_headers. append ( "Trailer" , "Lambda-Runtime-Function-Error-Type" . parse ( ) ?) ;
147164 req_headers. append ( "Trailer" , "Lambda-Runtime-Function-Error-Body" . parse ( ) ?) ;
165+
166+ if let Some ( id) = self . invocation_id {
167+ req_headers. append ( LAMBDA_RUNTIME_INVOCATION_ID , id. parse ( ) ?) ;
168+ }
169+
148170 req_headers. insert (
149171 "Content-Type" ,
150172 "application/vnd.awslambda.http-integration-response" . parse ( ) ?,
@@ -193,29 +215,22 @@ where
193215 }
194216}
195217
196- #[ test]
197- fn test_event_completion_request ( ) {
198- let req = EventCompletionRequest :: new ( "id" , "hello, world!" ) ;
199- let req = req. into_req ( ) . unwrap ( ) ;
200- let expected = Uri :: from_static ( "/2018-06-01/runtime/invocation/id/response" ) ;
201- assert_eq ! ( req. method( ) , Method :: POST ) ;
202- assert_eq ! ( req. uri( ) , & expected) ;
203- assert ! ( match req. headers( ) . get( "User-Agent" ) {
204- Some ( header) => header. to_str( ) . unwrap( ) . starts_with( "aws-lambda-rust/" ) ,
205- None => false ,
206- } ) ;
207- }
208-
209218// /runtime/invocation/{AwsRequestId}/error
210219pub ( crate ) struct EventErrorRequest < ' a > {
211220 pub ( crate ) request_id : & ' a str ,
221+ pub ( crate ) invocation_id : Option < & ' a str > ,
212222 pub ( crate ) diagnostic : Diagnostic ,
213223}
214224
215225impl < ' a > EventErrorRequest < ' a > {
216- pub ( crate ) fn new ( request_id : & ' a str , diagnostic : impl Into < Diagnostic > ) -> EventErrorRequest < ' a > {
226+ pub ( crate ) fn new (
227+ request_id : & ' a str ,
228+ invocation_id : Option < & ' a str > ,
229+ diagnostic : impl Into < Diagnostic > ,
230+ ) -> EventErrorRequest < ' a > {
217231 EventErrorRequest {
218232 request_id,
233+ invocation_id,
219234 diagnostic : diagnostic. into ( ) ,
220235 }
221236 }
@@ -228,11 +243,16 @@ impl IntoRequest for EventErrorRequest<'_> {
228243 let body = serde_json:: to_vec ( & self . diagnostic ) ?;
229244 let body = Body :: from ( body) ;
230245
231- let req = build_request ( )
246+ let mut req = build_request ( )
232247 . method ( Method :: POST )
233248 . uri ( uri)
234249 . header ( "lambda-runtime-function-error-type" , "unhandled" )
235250 . body ( body) ?;
251+
252+ if let Some ( id) = self . invocation_id {
253+ req. headers_mut ( ) . insert ( LAMBDA_RUNTIME_INVOCATION_ID , id. parse ( ) ?) ;
254+ }
255+
236256 Ok ( req)
237257 }
238258}
@@ -253,10 +273,93 @@ mod tests {
253273 } ) ;
254274 }
255275
276+ #[ test]
277+ fn test_event_completion_request ( ) {
278+ let req = EventCompletionRequest :: new ( "id" , Option :: Some ( "invocation_id" ) , "hello, world!" ) ;
279+ let req = req. into_req ( ) . unwrap ( ) ;
280+ let expected = Uri :: from_static ( "/2018-06-01/runtime/invocation/id/response" ) ;
281+ assert_eq ! ( req. method( ) , Method :: POST ) ;
282+ assert_eq ! ( req. uri( ) , & expected) ;
283+
284+ assert ! ( req
285+ . headers( )
286+ . get( "User-Agent" )
287+ . unwrap( )
288+ . to_str( )
289+ . unwrap( )
290+ . starts_with( "aws-lambda-rust/" ) ) ;
291+
292+ assert_eq ! (
293+ req. headers( ) . get( LAMBDA_RUNTIME_INVOCATION_ID ) . unwrap( ) ,
294+ "invocation_id"
295+ ) ;
296+ }
297+
298+ #[ test]
299+ fn test_event_completion_request_invocation_id_not_added_when_none ( ) {
300+ let req = EventCompletionRequest :: new ( "id" , Option :: None , "hello, world!" ) ;
301+ let req = req. into_req ( ) . unwrap ( ) ;
302+
303+ assert ! ( req. headers( ) . get( LAMBDA_RUNTIME_INVOCATION_ID ) . is_none( ) ) ;
304+ }
305+
306+ #[ test]
307+ fn test_streaming_event_completion_request_with_invocation_id ( ) {
308+ use crate :: StreamResponse ;
309+
310+ let runtime = tokio:: runtime:: Builder :: new_current_thread ( )
311+ . enable_all ( )
312+ . build ( )
313+ . unwrap ( ) ;
314+
315+ runtime. block_on ( async {
316+ let stream = tokio_stream:: iter ( vec ! [ Ok :: <Bytes , Error >( Bytes :: from_static( b"chunk" ) ) ] ) ;
317+ let stream_response: StreamResponse < _ > = stream. into ( ) ;
318+ let response = FunctionResponse :: StreamingResponse ( stream_response) ;
319+
320+ let req: EventCompletionRequest < ' _ , _ , ( ) , _ , _ , _ > =
321+ EventCompletionRequest :: new ( "id" , Some ( "invocation_id" ) , response) ;
322+
323+ let http_req = req. into_req ( ) . expect ( "into_req should succeed" ) ;
324+ let expected = Uri :: from_static ( "/2018-06-01/runtime/invocation/id/response" ) ;
325+ assert_eq ! ( http_req. method( ) , Method :: POST ) ;
326+ assert_eq ! ( http_req. uri( ) , & expected) ;
327+
328+ assert_eq ! (
329+ http_req. headers( ) . get( LAMBDA_RUNTIME_INVOCATION_ID ) . unwrap( ) ,
330+ "invocation_id"
331+ ) ;
332+ } ) ;
333+ }
334+
335+ #[ test]
336+ fn test_streaming_event_completion_request_invocation_id_not_added_when_none ( ) {
337+ use crate :: StreamResponse ;
338+
339+ let runtime = tokio:: runtime:: Builder :: new_current_thread ( )
340+ . enable_all ( )
341+ . build ( )
342+ . unwrap ( ) ;
343+
344+ runtime. block_on ( async {
345+ let stream = tokio_stream:: iter ( vec ! [ Ok :: <Bytes , Error >( Bytes :: from_static( b"chunk" ) ) ] ) ;
346+ let stream_response: StreamResponse < _ > = stream. into ( ) ;
347+ let response = FunctionResponse :: StreamingResponse ( stream_response) ;
348+
349+ let req: EventCompletionRequest < ' _ , _ , ( ) , _ , _ , _ > =
350+ EventCompletionRequest :: new ( "id" , None , response) ;
351+
352+ let http_req = req. into_req ( ) . expect ( "into_req should succeed" ) ;
353+
354+ assert ! ( http_req. headers( ) . get( LAMBDA_RUNTIME_INVOCATION_ID ) . is_none( ) ) ;
355+ } ) ;
356+ }
357+
256358 #[ test]
257359 fn test_event_error_request ( ) {
258360 let req = EventErrorRequest {
259361 request_id : "id" ,
362+ invocation_id : Option :: Some ( "invocation_id" ) ,
260363 diagnostic : Diagnostic {
261364 error_type : "InvalidEventDataError" . into ( ) ,
262365 error_message : "Error parsing event data" . into ( ) ,
@@ -270,6 +373,26 @@ mod tests {
270373 Some ( header) => header. to_str( ) . unwrap( ) . starts_with( "aws-lambda-rust/" ) ,
271374 None => false ,
272375 } ) ;
376+
377+ assert ! ( match req. headers( ) . get( LAMBDA_RUNTIME_INVOCATION_ID ) {
378+ Some ( header) => header. to_str( ) . unwrap( ) == "invocation_id" ,
379+ None => false ,
380+ } ) ;
381+ }
382+
383+ #[ test]
384+ fn test_event_error_request_invocation_id_not_added_when_none ( ) {
385+ let req = EventErrorRequest {
386+ request_id : "id" ,
387+ invocation_id : None ,
388+ diagnostic : Diagnostic {
389+ error_type : "InvalidEventDataError" . into ( ) ,
390+ error_message : "Error parsing event data" . into ( ) ,
391+ } ,
392+ } ;
393+ let req = req. into_req ( ) . unwrap ( ) ;
394+
395+ assert ! ( req. headers( ) . get( LAMBDA_RUNTIME_INVOCATION_ID ) . is_none( ) ) ;
273396 }
274397
275398 #[ test]
0 commit comments