@marcel91200 / caddy Mirror · read-only / commits / 10b265d2
Fork 0

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),