github.com/go-playground/pkg/v5@v5.29.1/net/http/helpers_go1.18.go (about)

     1  //go:build go1.18
     2  // +build go1.18
     3  
     4  package httpext
     5  
     6  import (
     7  	"errors"
     8  	"net/http"
     9  	"strconv"
    10  	"strings"
    11  	"time"
    12  
    13  	asciiext "github.com/go-playground/pkg/v5/ascii"
    14  	bytesext "github.com/go-playground/pkg/v5/bytes"
    15  	. "github.com/go-playground/pkg/v5/values/option"
    16  )
    17  
    18  // DecodeResponse takes the response and attempts to discover its content type via
    19  // the http headers and then decode the request body into the provided type.
    20  //
    21  // Example if header was "application/json" would decode using
    22  // json.NewDecoder(ioext.LimitReader(r.Body, maxBytes)).Decode(v).
    23  func DecodeResponse[T any](r *http.Response, maxMemory bytesext.Bytes) (result T, err error) {
    24  	typ := r.Header.Get(ContentType)
    25  	if idx := strings.Index(typ, ";"); idx != -1 {
    26  		typ = typ[:idx]
    27  	}
    28  	switch typ {
    29  	case nakedApplicationJSON:
    30  		err = decodeJSON(r.Header, r.Body, NoQueryParams, nil, maxMemory, &result)
    31  	case nakedApplicationXML:
    32  		err = decodeXML(r.Header, r.Body, NoQueryParams, nil, maxMemory, &result)
    33  	default:
    34  		err = errors.New("unsupported content type")
    35  	}
    36  	return
    37  }
    38  
    39  // HasRetryAfter parses the Retry-After header and returns the duration if possible.
    40  func HasRetryAfter(headers http.Header) Option[time.Duration] {
    41  	if ra := headers.Get(RetryAfter); ra != "" {
    42  		if asciiext.IsDigit(ra[0]) {
    43  			if n, err := strconv.ParseInt(ra, 10, 64); err == nil {
    44  				return Some(time.Duration(n) * time.Second)
    45  			}
    46  		} else {
    47  			// not a number so must be a date in the future
    48  			if t, err := http.ParseTime(ra); err == nil {
    49  				return Some(time.Until(t))
    50  			}
    51  		}
    52  	}
    53  	return None[time.Duration]()
    54  }