Skip to content

Commit 47e703d

Browse files
authored
Report errors returned by the response reader (#495)
1 parent 6645426 commit 47e703d

File tree

1 file changed

+33
-2
lines changed

1 file changed

+33
-2
lines changed

lambda/runtime_api_client.go

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package lambda
66

77
import (
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

108111
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)
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

Comments
 (0)