Codebase list golang-github-go-kit-kit / 0262bac
Merge pull request #533 from travissalascox/master added client finalizer Peter Bourgon authored 6 years ago GitHub committed 6 years ago
2 changed file(s) with 81 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
2222 dec DecodeResponseFunc
2323 before []RequestFunc
2424 after []ClientResponseFunc
25 finalizer ClientFinalizerFunc
2526 bufferedStream bool
2627 }
2728
7172 return func(c *Client) { c.after = append(c.after, after...) }
7273 }
7374
75 // ClientFinalizer is executed at the end of every HTTP request.
76 // By default, no finalizer is registered.
77 func ClientFinalizer(f ClientFinalizerFunc) ClientOption {
78 return func(s *Client) { s.finalizer = f }
79 }
80
7481 // BufferedStream sets whether the Response.Body is left open, allowing it
7582 // to be read from later. Useful for transporting a file as a buffered stream.
7683 func BufferedStream(buffered bool) ClientOption {
8289 return func(ctx context.Context, request interface{}) (interface{}, error) {
8390 ctx, cancel := context.WithCancel(ctx)
8491 defer cancel()
92
93 var (
94 resp *http.Response
95 err error
96 )
97 if c.finalizer != nil {
98 defer func() {
99 if resp != nil {
100 ctx = context.WithValue(ctx, ContextKeyResponseHeaders, resp.Header)
101 ctx = context.WithValue(ctx, ContextKeyResponseSize, resp.ContentLength)
102 }
103 c.finalizer(ctx, err)
104 }()
105 }
85106
86107 req, err := http.NewRequest(c.method, c.tgt.String(), nil)
87108 if err != nil {
96117 ctx = f(ctx, req)
97118 }
98119
99 resp, err := ctxhttp.Do(ctx, c.client, req)
120 resp, err = ctxhttp.Do(ctx, c.client, req)
100121 if err != nil {
101122 return nil, err
102123 }
124
103125 if !c.bufferedStream {
104126 defer resp.Body.Close()
105127 }
116138 return response, nil
117139 }
118140 }
141
142 // ClientFinalizerFunc can be used to perform work at the end of a client HTTP
143 // request, after the response is returned. The principal
144 // intended use is for error logging. Additional response parameters are
145 // provided in the context under keys with the ContextKeyResponse prefix.
146 // Note: err may be nil. There maybe also no additional response parameters depending on
147 // when an error occurs.
148 type ClientFinalizerFunc func(ctx context.Context, err error)
119149
120150 // EncodeJSONRequest is an EncodeRequestFunc that serializes the request as a
121151 // JSON object to the Request body. Many JSON-over-HTTP services can use it as
136136 }
137137 if want, have := testbody, string(b); want != have {
138138 t.Errorf("want %q, have %q", want, have)
139 }
140 }
141
142 func TestClientFinalizer(t *testing.T) {
143 var (
144 headerKey = "X-Henlo-Lizer"
145 headerVal = "Helllo you stinky lizard"
146 responseBody = "go eat a fly ugly\n"
147 done = make(chan struct{})
148 encode = func(context.Context, *http.Request, interface{}) error { return nil }
149 decode = func(_ context.Context, r *http.Response) (interface{}, error) {
150 return TestResponse{r.Body, ""}, nil
151 }
152 )
153
154 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
155 w.Header().Set(headerKey, headerVal)
156 w.Write([]byte(responseBody))
157 }))
158 defer server.Close()
159
160 client := httptransport.NewClient(
161 "GET",
162 mustParse(server.URL),
163 encode,
164 decode,
165 httptransport.ClientFinalizer(func(ctx context.Context, err error) {
166 responseHeader := ctx.Value(httptransport.ContextKeyResponseHeaders).(http.Header)
167 if want, have := headerVal, responseHeader.Get(headerKey); want != have {
168 t.Errorf("%s: want %q, have %q", headerKey, want, have)
169 }
170
171 responseSize := ctx.Value(httptransport.ContextKeyResponseSize).(int64)
172 if want, have := int64(len(responseBody)), responseSize; want != have {
173 t.Errorf("response size: want %d, have %d", want, have)
174 }
175
176 close(done)
177 }),
178 )
179
180 _, err := client.Endpoint()(context.Background(), struct{}{})
181 if err != nil {
182 t.Fatal(err)
183 }
184
185 select {
186 case <-done:
187 case <-time.After(time.Second):
188 t.Fatal("timeout waiting for finalizer")
139189 }
140190 }
141191