request.go raw
1 package session
2
3 import (
4 "bytes"
5 "encoding/json"
6 "errors"
7 "fmt"
8 "io"
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 = io.NopCloser(bytes.NewBuffer(data))
60 r.ContentLength = int64(len(data))
61 }
62
63 s.client.CheckRedirect = func(req *http.Request, _ []*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.Error("Failed to dump request", "error", err)
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.Error("Failed to dump response", "error", err)
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 := io.ReadAll(resp.Body)
98 if err != nil {
99 return nil, err
100 }
101 resp.Body = io.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 }
120