@@ -6,6 +6,7 @@ package lambda
6
6
7
7
import (
8
8
"bytes"
9
+ "encoding/base64"
9
10
"fmt"
10
11
"io"
11
12
"io/ioutil" //nolint: staticcheck
@@ -21,6 +22,8 @@ const (
21
22
headerCognitoIdentity = "Lambda-Runtime-Cognito-Identity"
22
23
headerClientContext = "Lambda-Runtime-Client-Context"
23
24
headerInvokedFunctionARN = "Lambda-Runtime-Invoked-Function-Arn"
25
+ trailerLambdaErrorType = "Lambda-Runtime-Function-Error-Type"
26
+ trailerLambdaErrorBody = "Lambda-Runtime-Function-Error-Body"
24
27
contentTypeJSON = "application/json"
25
28
contentTypeBytes = "application/octet-stream"
26
29
apiVersion = "2018-06-01"
@@ -106,10 +109,12 @@ func (c *runtimeAPIClient) next() (*invoke, error) {
106
109
}
107
110
108
111
func (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 )
110
114
if err != nil {
111
115
return fmt .Errorf ("failed to construct POST request to %s: %v" , url , err )
112
116
}
117
+ req .Trailer = b .Trailer
113
118
req .Header .Set ("User-Agent" , c .userAgent )
114
119
req .Header .Set ("Content-Type" , contentType )
115
120
@@ -122,7 +127,6 @@ func (c *runtimeAPIClient) post(url string, body io.Reader, contentType string)
122
127
log .Printf ("runtime API client failed to close %s response body: %v" , url , err )
123
128
}
124
129
}()
125
-
126
130
if resp .StatusCode != http .StatusAccepted {
127
131
return fmt .Errorf ("failed to POST to %s: got unexpected status code: %d" , url , resp .StatusCode )
128
132
}
@@ -134,3 +138,30 @@ func (c *runtimeAPIClient) post(url string, body io.Reader, contentType string)
134
138
135
139
return nil
136
140
}
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