code.dwrz.net

Go monorepo.
Log | Files | Refs

middleware_close_response_body.go (2597B)


      1 package http
      2 
      3 import (
      4 	"context"
      5 	"github.com/aws/smithy-go/logging"
      6 	"github.com/aws/smithy-go/middleware"
      7 	"io"
      8 	"io/ioutil"
      9 )
     10 
     11 // AddErrorCloseResponseBodyMiddleware adds the middleware to automatically
     12 // close the response body of an operation request if the request response
     13 // failed.
     14 func AddErrorCloseResponseBodyMiddleware(stack *middleware.Stack) error {
     15 	return stack.Deserialize.Insert(&errorCloseResponseBodyMiddleware{}, "OperationDeserializer", middleware.Before)
     16 }
     17 
     18 type errorCloseResponseBodyMiddleware struct{}
     19 
     20 func (*errorCloseResponseBodyMiddleware) ID() string {
     21 	return "ErrorCloseResponseBody"
     22 }
     23 
     24 func (m *errorCloseResponseBodyMiddleware) HandleDeserialize(
     25 	ctx context.Context, input middleware.DeserializeInput, next middleware.DeserializeHandler,
     26 ) (
     27 	output middleware.DeserializeOutput, metadata middleware.Metadata, err error,
     28 ) {
     29 	out, metadata, err := next.HandleDeserialize(ctx, input)
     30 	if err != nil {
     31 		if resp, ok := out.RawResponse.(*Response); ok && resp != nil && resp.Body != nil {
     32 			// Consume the full body to prevent TCP connection resets on some platforms
     33 			_, _ = io.Copy(ioutil.Discard, resp.Body)
     34 			// Do not validate that the response closes successfully.
     35 			resp.Body.Close()
     36 		}
     37 	}
     38 
     39 	return out, metadata, err
     40 }
     41 
     42 // AddCloseResponseBodyMiddleware adds the middleware to automatically close
     43 // the response body of an operation request, after the response had been
     44 // deserialized.
     45 func AddCloseResponseBodyMiddleware(stack *middleware.Stack) error {
     46 	return stack.Deserialize.Insert(&closeResponseBody{}, "OperationDeserializer", middleware.Before)
     47 }
     48 
     49 type closeResponseBody struct{}
     50 
     51 func (*closeResponseBody) ID() string {
     52 	return "CloseResponseBody"
     53 }
     54 
     55 func (m *closeResponseBody) HandleDeserialize(
     56 	ctx context.Context, input middleware.DeserializeInput, next middleware.DeserializeHandler,
     57 ) (
     58 	output middleware.DeserializeOutput, metadata middleware.Metadata, err error,
     59 ) {
     60 	out, metadata, err := next.HandleDeserialize(ctx, input)
     61 	if err != nil {
     62 		return out, metadata, err
     63 	}
     64 
     65 	if resp, ok := out.RawResponse.(*Response); ok {
     66 		// Consume the full body to prevent TCP connection resets on some platforms
     67 		_, copyErr := io.Copy(ioutil.Discard, resp.Body)
     68 		if copyErr != nil {
     69 			middleware.GetLogger(ctx).Logf(logging.Warn, "failed to discard remaining HTTP response body, this may affect connection reuse")
     70 		}
     71 
     72 		closeErr := resp.Body.Close()
     73 		if closeErr != nil {
     74 			middleware.GetLogger(ctx).Logf(logging.Warn, "failed to close HTTP response body, this may affect connection reuse")
     75 		}
     76 	}
     77 
     78 	return out, metadata, err
     79 }