github.com/akamai/AkamaiOPEN-edgegrid-golang/v2@v2.17.0/pkg/session/request.go (about)

     1  package session
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"net/http"
    10  	"net/http/httputil"
    11  )
    12  
    13  var (
    14  	// ErrInvalidArgument is returned when invalid number of arguments were supplied to a function
    15  	ErrInvalidArgument = errors.New("invalid arguments provided")
    16  	// ErrMarshaling represents marshaling error
    17  	ErrMarshaling = errors.New("marshaling input")
    18  	// ErrUnmarshaling represents unmarshaling error
    19  	ErrUnmarshaling = errors.New("unmarshaling output")
    20  )
    21  
    22  // Exec will sign and execute the request using the client edgegrid.Config
    23  func (s *session) Exec(r *http.Request, out interface{}, in ...interface{}) (*http.Response, error) {
    24  	if len(in) > 1 {
    25  		return nil, fmt.Errorf("%w: %s", ErrInvalidArgument, "'in' argument must have 0 or 1 value")
    26  	}
    27  	log := s.Log(r.Context())
    28  
    29  	// Apply any context header overrides
    30  	if o, ok := r.Context().Value(contextOptionKey).(*contextOptions); ok {
    31  		for k, v := range o.header {
    32  			r.Header[k] = v
    33  		}
    34  	}
    35  
    36  	r.URL.RawQuery = r.URL.Query().Encode()
    37  	if r.UserAgent() == "" {
    38  		r.Header.Set("User-Agent", s.userAgent)
    39  	}
    40  
    41  	if r.Header.Get("Content-Type") == "" {
    42  		r.Header.Set("Content-Type", "application/json")
    43  	}
    44  
    45  	if r.URL.Scheme == "" {
    46  		r.URL.Scheme = "https"
    47  	}
    48  
    49  	if len(in) > 0 {
    50  		data, err := json.Marshal(in[0])
    51  		if err != nil {
    52  			return nil, fmt.Errorf("%w: %s", ErrMarshaling, err)
    53  		}
    54  
    55  		r.Body = ioutil.NopCloser(bytes.NewBuffer(data))
    56  		r.ContentLength = int64(len(data))
    57  	}
    58  
    59  	s.client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
    60  		return s.Sign(req)
    61  	}
    62  
    63  	if err := s.Sign(r); err != nil {
    64  		return nil, err
    65  	}
    66  
    67  	if s.trace {
    68  		data, err := httputil.DumpRequestOut(r, true)
    69  		if err != nil {
    70  			log.WithError(err).Error("Failed to dump request")
    71  		} else {
    72  			log.Debug(string(data))
    73  		}
    74  	}
    75  
    76  	resp, err := s.client.Do(r)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  
    81  	if s.trace {
    82  		data, err := httputil.DumpResponse(resp, true)
    83  		if err != nil {
    84  			log.WithError(err).Error("Failed to dump response")
    85  		} else {
    86  			log.Debug(string(data))
    87  		}
    88  	}
    89  
    90  	if out != nil &&
    91  		resp.StatusCode >= http.StatusOK && resp.StatusCode < http.StatusMultipleChoices &&
    92  		resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusResetContent {
    93  		data, err := ioutil.ReadAll(resp.Body)
    94  		resp.Body = ioutil.NopCloser(bytes.NewBuffer(data))
    95  		if err != nil {
    96  			return nil, err
    97  		}
    98  
    99  		if err := json.Unmarshal(data, out); err != nil {
   100  			return nil, fmt.Errorf("%w: %s", ErrUnmarshaling, err)
   101  		}
   102  	}
   103  
   104  	return resp, nil
   105  }
   106  
   107  // Sign will only sign a request
   108  func (s *session) Sign(r *http.Request) error {
   109  	s.signer.SignRequest(r)
   110  	return nil
   111  }