@@ -6,6 +6,7 @@ package lambda
66
77import (
88 "bytes"
9+ "encoding/base64"
910 "fmt"
1011 "io"
1112 "io/ioutil" //nolint: staticcheck
@@ -21,6 +22,8 @@ const (
2122 headerCognitoIdentity = "Lambda-Runtime-Cognito-Identity"
2223 headerClientContext = "Lambda-Runtime-Client-Context"
2324 headerInvokedFunctionARN = "Lambda-Runtime-Invoked-Function-Arn"
25+ trailerLambdaErrorType = "Lambda-Runtime-Function-Error-Type"
26+ trailerLambdaErrorBody = "Lambda-Runtime-Function-Error-Body"
2427 contentTypeJSON = "application/json"
2528 contentTypeBytes = "application/octet-stream"
2629 apiVersion = "2018-06-01"
@@ -106,10 +109,12 @@ func (c *runtimeAPIClient) next() (*invoke, error) {
106109}
107110
108111func (c * runtimeAPIClient ) post (url string , body io.Reader , contentType string ) error {
109- req , err := http .NewRequest (http .MethodPost , url , body )
112+ b := newErrorCapturingReader (body )
113+ req , err := http .NewRequest (http .MethodPost , url , b )
110114 if err != nil {
111115 return fmt .Errorf ("failed to construct POST request to %s: %v" , url , err )
112116 }
117+ req .Trailer = b .Trailer
113118 req .Header .Set ("User-Agent" , c .userAgent )
114119 req .Header .Set ("Content-Type" , contentType )
115120
@@ -122,7 +127,6 @@ func (c *runtimeAPIClient) post(url string, body io.Reader, contentType string)
122127 log .Printf ("runtime API client failed to close %s response body: %v" , url , err )
123128 }
124129 }()
125-
126130 if resp .StatusCode != http .StatusAccepted {
127131 return fmt .Errorf ("failed to POST to %s: got unexpected status code: %d" , url , resp .StatusCode )
128132 }
@@ -134,3 +138,30 @@ func (c *runtimeAPIClient) post(url string, body io.Reader, contentType string)
134138
135139 return nil
136140}
141+
142+ func newErrorCapturingReader (r io.Reader ) * errorCapturingReader {
143+ trailer := http.Header {
144+ trailerLambdaErrorType : nil ,
145+ trailerLambdaErrorBody : nil ,
146+ }
147+ return & errorCapturingReader {r , trailer }
148+ }
149+
150+ type errorCapturingReader struct {
151+ reader io.Reader
152+ Trailer http.Header
153+ }
154+
155+ func (r * errorCapturingReader ) Read (p []byte ) (int , error ) {
156+ if r .reader == nil {
157+ return 0 , io .EOF
158+ }
159+ n , err := r .reader .Read (p )
160+ if err != nil && err != io .EOF {
161+ lambdaErr := lambdaErrorResponse (err )
162+ r .Trailer .Set (trailerLambdaErrorType , lambdaErr .Type )
163+ r .Trailer .Set (trailerLambdaErrorBody , base64 .StdEncoding .EncodeToString (safeMarshal (lambdaErr )))
164+ return 0 , io .EOF
165+ }
166+ return n , err
167+ }
0 commit comments