src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

middleware_close_response_body.go (3844B)


      1 package http
      2 
      3 import (
      4 	"context"
      5 	"io"
      6 
      7 	"github.com/aws/smithy-go/logging"
      8 	"github.com/aws/smithy-go/middleware"
      9 )
     10 
     11 // CloseResponseBody closes the HTTP response body. It leaves the body open only
     12 // for a successful response whose payload is a caller-owned stream (isStreaming
     13 // with a nil opErr); on error, or for a non-streaming response, it closes the
     14 // body — an error response body is diagnostic, not a caller-owned stream.
     15 func CloseResponseBody(ctx context.Context, resp *Response, isStreaming bool, opErr error) {
     16 	if resp == nil || resp.Body == nil {
     17 		return
     18 	}
     19 	if isStreaming && opErr == nil {
     20 		return
     21 	}
     22 
     23 	// Drain to EOF before closing; a body closed while unread prevents
     24 	// connection reuse.
     25 	if _, copyErr := io.Copy(io.Discard, resp.Body); copyErr != nil {
     26 		middleware.GetLogger(ctx).Logf(logging.Warn, "failed to discard remaining HTTP response body, this may affect connection reuse")
     27 	}
     28 
     29 	if closeErr := resp.Body.Close(); closeErr != nil {
     30 		middleware.GetLogger(ctx).Logf(logging.Warn, "failed to close HTTP response body, this may affect connection reuse")
     31 	}
     32 }
     33 
     34 // AddErrorCloseResponseBodyMiddleware adds the middleware to automatically
     35 // close the response body of an operation request if the request response
     36 // failed.
     37 //
     38 // Deprecated: generated operation deserializers now close the response body
     39 // via CloseResponseBody, so this middleware is no longer used.
     40 func AddErrorCloseResponseBodyMiddleware(stack *middleware.Stack) error {
     41 	return stack.Deserialize.Insert(&errorCloseResponseBodyMiddleware{}, "OperationDeserializer", middleware.Before)
     42 }
     43 
     44 type errorCloseResponseBodyMiddleware struct{}
     45 
     46 func (*errorCloseResponseBodyMiddleware) ID() string {
     47 	return "ErrorCloseResponseBody"
     48 }
     49 
     50 func (m *errorCloseResponseBodyMiddleware) HandleDeserialize(
     51 	ctx context.Context, input middleware.DeserializeInput, next middleware.DeserializeHandler,
     52 ) (
     53 	output middleware.DeserializeOutput, metadata middleware.Metadata, err error,
     54 ) {
     55 	out, metadata, err := next.HandleDeserialize(ctx, input)
     56 	if err != nil {
     57 		if resp, ok := out.RawResponse.(*Response); ok && resp != nil && resp.Body != nil {
     58 			// Consume the full body to prevent TCP connection resets on some platforms
     59 			_, _ = io.Copy(io.Discard, resp.Body)
     60 			// Do not validate that the response closes successfully.
     61 			resp.Body.Close()
     62 		}
     63 	}
     64 
     65 	return out, metadata, err
     66 }
     67 
     68 // AddCloseResponseBodyMiddleware adds the middleware to automatically close
     69 // the response body of an operation request, after the response had been
     70 // deserialized.
     71 //
     72 // Deprecated: generated operation deserializers now close the response body
     73 // via CloseResponseBody, so this middleware is no longer used.
     74 func AddCloseResponseBodyMiddleware(stack *middleware.Stack) error {
     75 	return stack.Deserialize.Insert(&closeResponseBody{}, "OperationDeserializer", middleware.Before)
     76 }
     77 
     78 type closeResponseBody struct{}
     79 
     80 func (*closeResponseBody) ID() string {
     81 	return "CloseResponseBody"
     82 }
     83 
     84 func (m *closeResponseBody) HandleDeserialize(
     85 	ctx context.Context, input middleware.DeserializeInput, next middleware.DeserializeHandler,
     86 ) (
     87 	output middleware.DeserializeOutput, metadata middleware.Metadata, err error,
     88 ) {
     89 	out, metadata, err := next.HandleDeserialize(ctx, input)
     90 	if err != nil {
     91 		return out, metadata, err
     92 	}
     93 
     94 	if resp, ok := out.RawResponse.(*Response); ok {
     95 		// Consume the full body to prevent TCP connection resets on some platforms
     96 		_, copyErr := io.Copy(io.Discard, resp.Body)
     97 		if copyErr != nil {
     98 			middleware.GetLogger(ctx).Logf(logging.Warn, "failed to discard remaining HTTP response body, this may affect connection reuse")
     99 		}
    100 
    101 		closeErr := resp.Body.Close()
    102 		if closeErr != nil {
    103 			middleware.GetLogger(ctx).Logf(logging.Warn, "failed to close HTTP response body, this may affect connection reuse")
    104 		}
    105 	}
    106 
    107 	return out, metadata, err
    108 }