Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 13, 05:30 UTC
reverseproxy: Header up/down support for CLI command (#5460)
Francis Lavoie committed
Mar 27, 2023 at 16:35 UTC
10b265d25279aa4aabdf3e390f580492cf0077f7
1 file changed
+59
-5
modules/caddyhttp/reverseproxy/command.go
+59
-5
@@ -19,6 +19,7 @@ import (
19
"fmt"
20
"net/http"
21
"strconv"
22
+ "strings"
23
24
"github.com/caddyserver/caddy/v2"
25
"github.com/caddyserver/caddy/v2/caddyconfig"
@@ -34,7 +35,7 @@ import (
35
func init() {
36
caddycmd.RegisterCommand(caddycmd.Command{
37
Name: "reverse-proxy",
37
- Usage: "[--from <addr>] [--to <addr>] [--change-host-header] [--insecure] [--internal-certs] [--disable-redirects] [--access-log]",
38
+ Usage: `[--from <addr>] [--to <addr>] [--change-host-header] [--insecure] [--internal-certs] [--disable-redirects] [--header-up "Field: value"] [--header-down "Field: value"] [--access-log] [--debug]`,
39
Short: "A quick and production-ready reverse proxy",
40
Long: `
41
A simple but production-ready reverse proxy. Useful for quick deployments,
@@ -57,8 +58,11 @@ If serving HTTPS:
58
CA instead of attempting to issue a public certificate.
59
60
For proxying:
61
+ --header-up can be used to set a request header to send to the upstream.
62
+ --header-down can be used to set a response header to send back to the client.
63
--change-host-header sets the Host header on the request to the address
64
of the upstream, instead of defaulting to the incoming Host header.
65
+ This is a shortcut for --header-up "Host: {http.reverse_proxy.upstream.hostport}".
66
--insecure disables TLS verification with the upstream. WARNING: THIS
67
DISABLES SECURITY BY NOT VERIFYING THE UPSTREAM'S CERTIFICATE.
68
`,
@@ -69,6 +73,8 @@ For proxying:
73
cmd.Flags().BoolP("insecure", "", false, "Disable TLS verification (WARNING: DISABLES SECURITY BY NOT VERIFYING TLS CERTIFICATES!)")
74
cmd.Flags().BoolP("disable-redirects", "r", false, "Disable HTTP->HTTPS redirects")
75
cmd.Flags().BoolP("internal-certs", "i", false, "Use internal CA for issuing certs")
76
+ cmd.Flags().StringSliceP("header-up", "H", []string{}, "Set a request header to send to the upstream (format: \"Field: value\")")
77
+ cmd.Flags().StringSliceP("header-down", "d", []string{}, "Set a response header to send back to the client (format: \"Field: value\")")
78
cmd.Flags().BoolP("access-log", "", false, "Enable the access log")
79
cmd.Flags().BoolP("debug", "v", false, "Enable verbose debug logs")
80
cmd.RunE = caddycmd.WrapCommandFuncForCobra(cmdReverseProxy)
@@ -157,16 +163,64 @@ func cmdReverseProxy(fs caddycmd.Flags) (int, error) {
163
Upstreams: upstreamPool,
164
}
165
160
- if changeHost {
166
+ // set up header_up
167
+ headerUp, err := fs.GetStringSlice("header-up")
168
+ if err != nil {
169
+ return caddy.ExitCodeFailedStartup, fmt.Errorf("invalid header flag: %v", err)
170
+ }
171
+ if len(headerUp) > 0 {
172
+ reqHdr := make(http.Header)
173
+ for i, h := range headerUp {
174
+ key, val, found := strings.Cut(h, ":")
175
+ key, val = strings.TrimSpace(key), strings.TrimSpace(val)
176
+ if !found || key == "" || val == "" {
177
+ return caddy.ExitCodeFailedStartup, fmt.Errorf("header-up %d: invalid format \"%s\" (expecting \"Field: value\")", i, h)
178
+ }
179
+ reqHdr.Set(key, val)
180
+ }
181
handler.Headers = &headers.Handler{
182
Request: &headers.HeaderOps{
163
- Set: http.Header{
164
- "Host": []string{"{http.reverse_proxy.upstream.hostport}"},
165
- },
183
+ Set: reqHdr,
184
+ },
185
+ }
186
+ }
187
+
188
+ // set up header_down
189
+ headerDown, err := fs.GetStringSlice("header-down")
190
+ if err != nil {
191
+ return caddy.ExitCodeFailedStartup, fmt.Errorf("invalid header flag: %v", err)
192
+ }
193
+ if len(headerDown) > 0 {
194
+ respHdr := make(http.Header)
195
+ for i, h := range headerDown {
196
+ key, val, found := strings.Cut(h, ":")
197
+ key, val = strings.TrimSpace(key), strings.TrimSpace(val)
198
+ if !found || key == "" || val == "" {
199
+ return caddy.ExitCodeFailedStartup, fmt.Errorf("header-down %d: invalid format \"%s\" (expecting \"Field: value\")", i, h)
200
+ }
201
+ respHdr.Set(key, val)
202
+ }
203
+ if handler.Headers == nil {
204
+ handler.Headers = &headers.Handler{}
205
+ }
206
+ handler.Headers.Response = &headers.RespHeaderOps{
207
+ HeaderOps: &headers.HeaderOps{
208
+ Set: respHdr,
209
},
210
}
211
}
212
213
+ if changeHost {
214
+ if handler.Headers == nil {
215
+ handler.Headers = &headers.Handler{
216
+ Request: &headers.HeaderOps{
217
+ Set: http.Header{},
218
+ },
219
+ }
220
+ }
221
+ handler.Headers.Request.Set.Set("Host", "{http.reverse_proxy.upstream.hostport}")
222
+ }
223
+
224
route := caddyhttp.Route{
225
HandlersRaw: []json.RawMessage{
226
caddyconfig.JSONModuleObject(handler, "handler", "reverse_proxy", nil),