aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/hashicorp/vault/api/request.go
blob: 5bcff8c6c5100b3c5086b577f474317d7eccd6d6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package api

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"

	retryablehttp "github.com/hashicorp/go-retryablehttp"
)

// Request is a raw request configuration structure used to initiate
// API requests to the Vault server.
type Request struct {
	Method        string
	URL           *url.URL
	Params        url.Values
	Headers       http.Header
	ClientToken   string
	MFAHeaderVals []string
	WrapTTL       string
	Obj           interface{}

	// When possible, use BodyBytes as it is more efficient due to how the
	// retry logic works
	BodyBytes []byte

	// Fallback
	Body     io.Reader
	BodySize int64

	// Whether to request overriding soft-mandatory Sentinel policies (RGPs and
	// EGPs). If set, the override flag will take effect for all policies
	// evaluated during the request.
	PolicyOverride bool
}

// SetJSONBody is used to set a request body that is a JSON-encoded value.
func (r *Request) SetJSONBody(val interface{}) error {
	buf, err := json.Marshal(val)
	if err != nil {
		return err
	}

	r.Obj = val
	r.BodyBytes = buf
	return nil
}

// ResetJSONBody is used to reset the body for a redirect
func (r *Request) ResetJSONBody() error {
	if r.BodyBytes == nil {
		return nil
	}
	return r.SetJSONBody(r.Obj)
}

// DEPRECATED: ToHTTP turns this request into a valid *http.Request for use
// with the net/http package.
func (r *Request) ToHTTP() (*http.Request, error) {
	req, err := r.toRetryableHTTP()
	if err != nil {
		return nil, err
	}

	switch {
	case r.BodyBytes == nil && r.Body == nil:
		// No body

	case r.BodyBytes != nil:
		req.Request.Body = ioutil.NopCloser(bytes.NewReader(r.BodyBytes))

	default:
		if c, ok := r.Body.(io.ReadCloser); ok {
			req.Request.Body = c
		} else {
			req.Request.Body = ioutil.NopCloser(r.Body)
		}
	}

	return req.Request, nil
}

func (r *Request) toRetryableHTTP() (*retryablehttp.Request, error) {
	// Encode the query parameters
	r.URL.RawQuery = r.Params.Encode()

	// Create the HTTP request, defaulting to retryable
	var req *retryablehttp.Request

	var err error
	var body interface{}

	switch {
	case r.BodyBytes == nil && r.Body == nil:
		// No body

	case r.BodyBytes != nil:
		// Use bytes, it's more efficient
		body = r.BodyBytes

	default:
		body = r.Body
	}

	req, err = retryablehttp.NewRequest(r.Method, r.URL.RequestURI(), body)
	if err != nil {
		return nil, err
	}

	req.URL.User = r.URL.User
	req.URL.Scheme = r.URL.Scheme
	req.URL.Host = r.URL.Host
	req.Host = r.URL.Host

	if r.Headers != nil {
		for header, vals := range r.Headers {
			for _, val := range vals {
				req.Header.Add(header, val)
			}
		}
	}

	if len(r.ClientToken) != 0 {
		req.Header.Set("X-Vault-Token", r.ClientToken)
	}

	if len(r.WrapTTL) != 0 {
		req.Header.Set("X-Vault-Wrap-TTL", r.WrapTTL)
	}

	if len(r.MFAHeaderVals) != 0 {
		for _, mfaHeaderVal := range r.MFAHeaderVals {
			req.Header.Add("X-Vault-MFA", mfaHeaderVal)
		}
	}

	if r.PolicyOverride {
		req.Header.Set("X-Vault-Policy-Override", "true")
	}

	return req, nil
}