github.com/akamai/AkamaiOPEN-edgegrid-golang/v8@v8.1.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.Header.Get("Accept") == "" {
    46  		r.Header.Set("Accept", "application/json")
    47  	}
    48  
    49  	if r.URL.Scheme == "" {
    50  		r.URL.Scheme = "https"
    51  	}
    52  
    53  	if len(in) > 0 {
    54  		data, err := json.Marshal(in[0])
    55  		if err != nil {
    56  			return nil, fmt.Errorf("%w: %s", ErrMarshaling, err)
    57  		}
    58  
    59  		r.Body = ioutil.NopCloser(bytes.NewBuffer(data))
    60  		r.ContentLength = int64(len(data))
    61  	}
    62  
    63  	s.client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
    64  		return s.Sign(req)
    65  	}
    66  
    67  	if err := s.Sign(r); err != nil {
    68  		return nil, err
    69  	}
    70  
    71  	if s.trace {
    72  		data, err := httputil.DumpRequestOut(r, true)
    73  		if err != nil {
    74  			log.WithError(err).Error("Failed to dump request")
    75  		} else {
    76  			log.Debug(string(data))
    77  		}
    78  	}
    79  
    80  	resp, err := s.client.Do(r)
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  
    85  	if s.trace {
    86  		data, err := httputil.DumpResponse(resp, true)
    87  		if err != nil {
    88  			log.WithError(err).Error("Failed to dump response")
    89  		} else {
    90  			log.Debug(string(data))
    91  		}
    92  	}
    93  
    94  	if out != nil &&
    95  		resp.StatusCode >= http.StatusOK && resp.StatusCode < http.StatusMultipleChoices &&
    96  		resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusResetContent {
    97  		data, err := ioutil.ReadAll(resp.Body)
    98  		if err != nil {
    99  			return nil, err
   100  		}
   101  		resp.Body = ioutil.NopCloser(bytes.NewBuffer(data))
   102  
   103  		if err := json.Unmarshal(data, out); err != nil {
   104  			return nil, fmt.Errorf("%w: %s", ErrUnmarshaling, err)
   105  		}
   106  	}
   107  
   108  	return resp, nil
   109  }
   110  
   111  // Sign will only sign a request
   112  func (s *session) Sign(r *http.Request) error {
   113  	s.signer.SignRequest(r)
   114  
   115  	if s.requestLimit != 0 {
   116  		s.signer.CheckRequestLimit(s.requestLimit)
   117  	}
   118  	return nil
   119  }