diff --git a/caddy.go b/caddy.go index c654fbe0..d010f630 100644 --- a/caddy.go +++ b/caddy.go @@ -136,10 +136,10 @@ type App interface { // Config represents a Caddy configuration. type Config struct { - StorageRaw json.RawMessage `json:"storage"` + StorageRaw json.RawMessage `json:"storage,omitempty"` storage certmagic.Storage - AppsRaw map[string]json.RawMessage `json:"apps"` + AppsRaw map[string]json.RawMessage `json:"apps,omitempty"` // apps stores the decoded Apps values, // keyed by module name. diff --git a/modules/caddyhttp/caddyhttp.go b/modules/caddyhttp/caddyhttp.go index 09a130e1..2b194cd9 100644 --- a/modules/caddyhttp/caddyhttp.go +++ b/modules/caddyhttp/caddyhttp.go @@ -32,10 +32,10 @@ func init() { // App is the HTTP app for Caddy. type App struct { - HTTPPort int `json:"http_port"` - HTTPSPort int `json:"https_port"` - GracePeriod caddy2.Duration `json:"grace_period"` - Servers map[string]*Server `json:"servers"` + HTTPPort int `json:"http_port,omitempty"` + HTTPSPort int `json:"https_port,omitempty"` + GracePeriod caddy2.Duration `json:"grace_period,omitempty"` + Servers map[string]*Server `json:"servers,omitempty"` servers []*http.Server @@ -188,7 +188,7 @@ func (app *App) automaticHTTPS() error { domainSet := make(map[string]struct{}) for _, route := range srv.Routes { for _, m := range route.matchers { - if hm, ok := m.(*matchHost); ok { + if hm, ok := m.(*MatchHost); ok { for _, d := range *hm { if !certmagic.HostQualifies(d) { continue @@ -246,8 +246,8 @@ func (app *App) automaticHTTPS() error { redirRoutes = append(redirRoutes, ServerRoute{ matchers: []RequestMatcher{ - matchProtocol("http"), - matchHost(domains), + MatchProtocol("http"), + MatchHost(domains), }, responder: Static{ StatusCode: http.StatusTemporaryRedirect, // TODO: use permanent redirect instead diff --git a/modules/caddyhttp/fileserver/browse.go b/modules/caddyhttp/fileserver/browse.go index 98698011..bf063e51 100644 --- a/modules/caddyhttp/fileserver/browse.go +++ b/modules/caddyhttp/fileserver/browse.go @@ -15,7 +15,7 @@ import ( // Browse configures directory browsing. type Browse struct { - TemplateFile string `json:"template_file"` + TemplateFile string `json:"template_file,omitempty"` template *template.Template } diff --git a/modules/caddyhttp/fileserver/staticfiles.go b/modules/caddyhttp/fileserver/staticfiles.go index c6a01ac3..08f92bf3 100644 --- a/modules/caddyhttp/fileserver/staticfiles.go +++ b/modules/caddyhttp/fileserver/staticfiles.go @@ -27,14 +27,14 @@ func init() { // FileServer implements a static file server responder for Caddy. type FileServer struct { - Root string `json:"root"` // default is current directory - Hide []string `json:"hide"` - IndexNames []string `json:"index_names"` - Files []string `json:"files"` // all relative to the root; default is request URI path - SelectionPolicy string `json:"selection_policy"` - Rehandle bool `json:"rehandle"` // issue a rehandle (internal redirect) if request is rewritten - Fallback caddyhttp.RouteList `json:"fallback"` - Browse *Browse `json:"browse"` + Root string `json:"root,omitempty"` // default is current directory + Hide []string `json:"hide,omitempty"` + IndexNames []string `json:"index_names,omitempty"` + Files []string `json:"files,omitempty"` // all relative to the root; default is request URI path + SelectionPolicy string `json:"selection_policy,omitempty"` + Rehandle bool `json:"rehandle,omitempty"` // issue a rehandle (internal redirect) if request is rewritten + Fallback caddyhttp.RouteList `json:"fallback,omitempty"` + Browse *Browse `json:"browse,omitempty"` // TODO: Etag // TODO: Content negotiation } diff --git a/modules/caddyhttp/headers/headers.go b/modules/caddyhttp/headers/headers.go index e94fb54c..4cab5b5c 100644 --- a/modules/caddyhttp/headers/headers.go +++ b/modules/caddyhttp/headers/headers.go @@ -17,22 +17,22 @@ func init() { // Headers is a middleware which can mutate HTTP headers. type Headers struct { - Request HeaderOps `json:"request"` - Response RespHeaderOps `json:"response"` + Request *HeaderOps `json:"request,omitempty"` + Response *RespHeaderOps `json:"response,omitempty"` } // HeaderOps defines some operations to // perform on HTTP headers. type HeaderOps struct { - Add http.Header `json:"add"` - Set http.Header `json:"set"` - Delete []string `json:"delete"` + Add http.Header `json:"add,omitempty"` + Set http.Header `json:"set,omitempty"` + Delete []string `json:"delete,omitempty"` } // RespHeaderOps is like HeaderOps, but // optionally deferred until response time. type RespHeaderOps struct { - HeaderOps + *HeaderOps Deferred bool `json:"deferred"` } @@ -51,7 +51,7 @@ func (h Headers) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhtt return next.ServeHTTP(w, r) } -func apply(ops HeaderOps, hdr http.Header, repl caddy2.Replacer) { +func apply(ops *HeaderOps, hdr http.Header, repl caddy2.Replacer) { for fieldName, vals := range ops.Add { fieldName = repl.ReplaceAll(fieldName, "") for _, v := range vals { @@ -75,7 +75,7 @@ func apply(ops HeaderOps, hdr http.Header, repl caddy2.Replacer) { type responseWriterWrapper struct { *caddyhttp.ResponseWriterWrapper replacer caddy2.Replacer - headerOps HeaderOps + headerOps *HeaderOps wroteHeader bool } diff --git a/modules/caddyhttp/matchers.go b/modules/caddyhttp/matchers.go index 64a93125..eb57156c 100644 --- a/modules/caddyhttp/matchers.go +++ b/modules/caddyhttp/matchers.go @@ -17,58 +17,58 @@ import ( ) type ( - matchHost []string - matchPath []string - matchPathRE struct{ matchRegexp } - matchMethod []string - matchQuery url.Values - matchHeader http.Header - matchHeaderRE map[string]*matchRegexp - matchProtocol string - matchStarlarkExpr string - matchTable string // TODO: finish implementing + MatchHost []string + MatchPath []string + MatchPathRE struct{ matchRegexp } + MatchMethod []string + MatchQuery url.Values + MatchHeader http.Header + MatchHeaderRE map[string]*matchRegexp + MatchProtocol string + MatchStarlarkExpr string + MatchTable string // TODO: finish implementing ) func init() { caddy2.RegisterModule(caddy2.Module{ Name: "http.matchers.host", - New: func() interface{} { return matchHost{} }, + New: func() interface{} { return MatchHost{} }, }) caddy2.RegisterModule(caddy2.Module{ Name: "http.matchers.path", - New: func() interface{} { return matchPath{} }, + New: func() interface{} { return MatchPath{} }, }) caddy2.RegisterModule(caddy2.Module{ Name: "http.matchers.path_regexp", - New: func() interface{} { return new(matchPathRE) }, + New: func() interface{} { return new(MatchPathRE) }, }) caddy2.RegisterModule(caddy2.Module{ Name: "http.matchers.method", - New: func() interface{} { return matchMethod{} }, + New: func() interface{} { return MatchMethod{} }, }) caddy2.RegisterModule(caddy2.Module{ Name: "http.matchers.query", - New: func() interface{} { return matchQuery{} }, + New: func() interface{} { return MatchQuery{} }, }) caddy2.RegisterModule(caddy2.Module{ Name: "http.matchers.header", - New: func() interface{} { return matchHeader{} }, + New: func() interface{} { return MatchHeader{} }, }) caddy2.RegisterModule(caddy2.Module{ Name: "http.matchers.header_regexp", - New: func() interface{} { return matchHeaderRE{} }, + New: func() interface{} { return MatchHeaderRE{} }, }) caddy2.RegisterModule(caddy2.Module{ Name: "http.matchers.protocol", - New: func() interface{} { return new(matchProtocol) }, + New: func() interface{} { return new(MatchProtocol) }, }) caddy2.RegisterModule(caddy2.Module{ Name: "http.matchers.starlark_expr", - New: func() interface{} { return new(matchStarlarkExpr) }, + New: func() interface{} { return new(MatchStarlarkExpr) }, }) } -func (m matchHost) Match(r *http.Request) bool { +func (m MatchHost) Match(r *http.Request) bool { outer: for _, host := range m { if strings.Contains(host, "*") { @@ -93,7 +93,7 @@ outer: return false } -func (m matchPath) Match(r *http.Request) bool { +func (m MatchPath) Match(r *http.Request) bool { for _, matchPath := range m { compare := r.URL.Path if strings.HasPrefix(matchPath, "*") { @@ -111,12 +111,12 @@ func (m matchPath) Match(r *http.Request) bool { return false } -func (m matchPathRE) Match(r *http.Request) bool { +func (m MatchPathRE) Match(r *http.Request) bool { repl := r.Context().Value(caddy2.ReplacerCtxKey).(caddy2.Replacer) return m.match(r.URL.Path, repl, "path_regexp") } -func (m matchMethod) Match(r *http.Request) bool { +func (m MatchMethod) Match(r *http.Request) bool { for _, method := range m { if r.Method == method { return true @@ -125,7 +125,7 @@ func (m matchMethod) Match(r *http.Request) bool { return false } -func (m matchQuery) Match(r *http.Request) bool { +func (m MatchQuery) Match(r *http.Request) bool { for param, vals := range m { paramVal := r.URL.Query().Get(param) for _, v := range vals { @@ -137,7 +137,7 @@ func (m matchQuery) Match(r *http.Request) bool { return false } -func (m matchHeader) Match(r *http.Request) bool { +func (m MatchHeader) Match(r *http.Request) bool { for field, allowedFieldVals := range m { var match bool actualFieldVals := r.Header[textproto.CanonicalMIMEHeaderKey(field)] @@ -157,7 +157,7 @@ func (m matchHeader) Match(r *http.Request) bool { return true } -func (m matchHeaderRE) Match(r *http.Request) bool { +func (m MatchHeaderRE) Match(r *http.Request) bool { for field, rm := range m { repl := r.Context().Value(caddy2.ReplacerCtxKey).(caddy2.Replacer) match := rm.match(r.Header.Get(field), repl, "header_regexp") @@ -168,7 +168,7 @@ func (m matchHeaderRE) Match(r *http.Request) bool { return true } -func (m matchHeaderRE) Provision() error { +func (m MatchHeaderRE) Provision() error { for _, rm := range m { err := rm.Provision() if err != nil { @@ -178,7 +178,7 @@ func (m matchHeaderRE) Provision() error { return nil } -func (m matchHeaderRE) Validate() error { +func (m MatchHeaderRE) Validate() error { for _, rm := range m { err := rm.Validate() if err != nil { @@ -188,7 +188,7 @@ func (m matchHeaderRE) Validate() error { return nil } -func (m matchProtocol) Match(r *http.Request) bool { +func (m MatchProtocol) Match(r *http.Request) bool { switch string(m) { case "grpc": return r.Header.Get("content-type") == "application/grpc" @@ -200,7 +200,7 @@ func (m matchProtocol) Match(r *http.Request) bool { return false } -func (m matchStarlarkExpr) Match(r *http.Request) bool { +func (m MatchStarlarkExpr) Match(r *http.Request) bool { input := string(m) thread := new(starlark.Thread) env := caddyscript.MatcherEnv(r) @@ -264,13 +264,13 @@ var wordRE = regexp.MustCompile(`\w+`) // Interface guards var ( - _ RequestMatcher = (*matchHost)(nil) - _ RequestMatcher = (*matchPath)(nil) - _ RequestMatcher = (*matchPathRE)(nil) - _ RequestMatcher = (*matchMethod)(nil) - _ RequestMatcher = (*matchQuery)(nil) - _ RequestMatcher = (*matchHeader)(nil) - _ RequestMatcher = (*matchHeaderRE)(nil) - _ RequestMatcher = (*matchProtocol)(nil) - _ RequestMatcher = (*matchStarlarkExpr)(nil) + _ RequestMatcher = (*MatchHost)(nil) + _ RequestMatcher = (*MatchPath)(nil) + _ RequestMatcher = (*MatchPathRE)(nil) + _ RequestMatcher = (*MatchMethod)(nil) + _ RequestMatcher = (*MatchQuery)(nil) + _ RequestMatcher = (*MatchHeader)(nil) + _ RequestMatcher = (*MatchHeaderRE)(nil) + _ RequestMatcher = (*MatchProtocol)(nil) + _ RequestMatcher = (*MatchStarlarkExpr)(nil) ) diff --git a/modules/caddyhttp/matchers_test.go b/modules/caddyhttp/matchers_test.go index 59b8c767..30b45f68 100644 --- a/modules/caddyhttp/matchers_test.go +++ b/modules/caddyhttp/matchers_test.go @@ -13,77 +13,77 @@ import ( func TestHostMatcher(t *testing.T) { for i, tc := range []struct { - match matchHost + match MatchHost input string expect bool }{ { - match: matchHost{}, + match: MatchHost{}, input: "example.com", expect: false, }, { - match: matchHost{"example.com"}, + match: MatchHost{"example.com"}, input: "example.com", expect: true, }, { - match: matchHost{"example.com"}, + match: MatchHost{"example.com"}, input: "foo.example.com", expect: false, }, { - match: matchHost{"example.com"}, + match: MatchHost{"example.com"}, input: "EXAMPLE.COM", expect: true, }, { - match: matchHost{"foo.example.com"}, + match: MatchHost{"foo.example.com"}, input: "foo.example.com", expect: true, }, { - match: matchHost{"foo.example.com"}, + match: MatchHost{"foo.example.com"}, input: "bar.example.com", expect: false, }, { - match: matchHost{"*.example.com"}, + match: MatchHost{"*.example.com"}, input: "example.com", expect: false, }, { - match: matchHost{"*.example.com"}, + match: MatchHost{"*.example.com"}, input: "foo.example.com", expect: true, }, { - match: matchHost{"*.example.com"}, + match: MatchHost{"*.example.com"}, input: "foo.bar.example.com", expect: false, }, { - match: matchHost{"*.example.com", "example.net"}, + match: MatchHost{"*.example.com", "example.net"}, input: "example.net", expect: true, }, { - match: matchHost{"example.net", "*.example.com"}, + match: MatchHost{"example.net", "*.example.com"}, input: "foo.example.com", expect: true, }, { - match: matchHost{"*.example.net", "*.*.example.com"}, + match: MatchHost{"*.example.net", "*.*.example.com"}, input: "foo.bar.example.com", expect: true, }, { - match: matchHost{"*.example.net", "sub.*.example.com"}, + match: MatchHost{"*.example.net", "sub.*.example.com"}, input: "sub.foo.example.com", expect: true, }, { - match: matchHost{"*.example.net", "sub.*.example.com"}, + match: MatchHost{"*.example.net", "sub.*.example.com"}, input: "sub.foo.example.net", expect: false, }, @@ -99,57 +99,57 @@ func TestHostMatcher(t *testing.T) { func TestPathMatcher(t *testing.T) { for i, tc := range []struct { - match matchPath + match MatchPath input string expect bool }{ { - match: matchPath{}, + match: MatchPath{}, input: "/", expect: false, }, { - match: matchPath{"/"}, + match: MatchPath{"/"}, input: "/", expect: true, }, { - match: matchPath{"/foo/bar"}, + match: MatchPath{"/foo/bar"}, input: "/", expect: false, }, { - match: matchPath{"/foo/bar"}, + match: MatchPath{"/foo/bar"}, input: "/foo/bar", expect: true, }, { - match: matchPath{"/foo/bar/"}, + match: MatchPath{"/foo/bar/"}, input: "/foo/bar", expect: false, }, { - match: matchPath{"/foo/bar/", "/other"}, + match: MatchPath{"/foo/bar/", "/other"}, input: "/other/", expect: true, }, { - match: matchPath{"*.ext"}, + match: MatchPath{"*.ext"}, input: "foo.ext", expect: true, }, { - match: matchPath{"*.ext"}, + match: MatchPath{"*.ext"}, input: "/foo/bar.ext", expect: true, }, { - match: matchPath{"/foo/*/baz"}, + match: MatchPath{"/foo/*/baz"}, input: "/foo/bar/baz", expect: true, }, { - match: matchPath{"/foo/*/baz/bam"}, + match: MatchPath{"/foo/*/baz/bam"}, input: "/foo/bar/bam", expect: false, }, @@ -165,49 +165,49 @@ func TestPathMatcher(t *testing.T) { func TestPathREMatcher(t *testing.T) { for i, tc := range []struct { - match matchPathRE + match MatchPathRE input string expect bool expectRepl map[string]string }{ { - match: matchPathRE{}, + match: MatchPathRE{}, input: "/", expect: true, }, { - match: matchPathRE{matchRegexp{Pattern: "/"}}, + match: MatchPathRE{matchRegexp{Pattern: "/"}}, input: "/", expect: true, }, { - match: matchPathRE{matchRegexp{Pattern: "/foo"}}, + match: MatchPathRE{matchRegexp{Pattern: "/foo"}}, input: "/foo", expect: true, }, { - match: matchPathRE{matchRegexp{Pattern: "/foo"}}, + match: MatchPathRE{matchRegexp{Pattern: "/foo"}}, input: "/foo/", expect: true, }, { - match: matchPathRE{matchRegexp{Pattern: "/bar"}}, + match: MatchPathRE{matchRegexp{Pattern: "/bar"}}, input: "/foo/", expect: false, }, { - match: matchPathRE{matchRegexp{Pattern: "^/bar"}}, + match: MatchPathRE{matchRegexp{Pattern: "^/bar"}}, input: "/foo/bar", expect: false, }, { - match: matchPathRE{matchRegexp{Pattern: "^/foo/(.*)/baz$", Name: "name"}}, + match: MatchPathRE{matchRegexp{Pattern: "^/foo/(.*)/baz$", Name: "name"}}, input: "/foo/bar/baz", expect: true, expectRepl: map[string]string{"name.1": "bar"}, }, { - match: matchPathRE{matchRegexp{Pattern: "^/foo/(?P.*)/baz$", Name: "name"}}, + match: MatchPathRE{matchRegexp{Pattern: "^/foo/(?P.*)/baz$", Name: "name"}}, input: "/foo/bar/baz", expect: true, expectRepl: map[string]string{"name.myparam": "bar"}, @@ -253,47 +253,47 @@ func TestPathREMatcher(t *testing.T) { func TestHeaderMatcher(t *testing.T) { for i, tc := range []struct { - match matchHeader + match MatchHeader input http.Header // make sure these are canonical cased (std lib will do that in a real request) expect bool }{ { - match: matchHeader{"Field": []string{"foo"}}, + match: MatchHeader{"Field": []string{"foo"}}, input: http.Header{"Field": []string{"foo"}}, expect: true, }, { - match: matchHeader{"Field": []string{"foo", "bar"}}, + match: MatchHeader{"Field": []string{"foo", "bar"}}, input: http.Header{"Field": []string{"bar"}}, expect: true, }, { - match: matchHeader{"Field": []string{"foo", "bar"}}, + match: MatchHeader{"Field": []string{"foo", "bar"}}, input: http.Header{"Alakazam": []string{"kapow"}}, expect: false, }, { - match: matchHeader{"Field": []string{"foo", "bar"}}, + match: MatchHeader{"Field": []string{"foo", "bar"}}, input: http.Header{"Field": []string{"kapow"}}, expect: false, }, { - match: matchHeader{"Field": []string{"foo", "bar"}}, + match: MatchHeader{"Field": []string{"foo", "bar"}}, input: http.Header{"Field": []string{"kapow", "foo"}}, expect: true, }, { - match: matchHeader{"Field1": []string{"foo"}, "Field2": []string{"bar"}}, + match: MatchHeader{"Field1": []string{"foo"}, "Field2": []string{"bar"}}, input: http.Header{"Field1": []string{"foo"}, "Field2": []string{"bar"}}, expect: true, }, { - match: matchHeader{"field1": []string{"foo"}, "field2": []string{"bar"}}, + match: MatchHeader{"field1": []string{"foo"}, "field2": []string{"bar"}}, input: http.Header{"Field1": []string{"foo"}, "Field2": []string{"bar"}}, expect: true, }, { - match: matchHeader{"field1": []string{"foo"}, "field2": []string{"bar"}}, + match: MatchHeader{"field1": []string{"foo"}, "field2": []string{"bar"}}, input: http.Header{"Field1": []string{"foo"}, "Field2": []string{"kapow"}}, expect: false, }, @@ -309,23 +309,23 @@ func TestHeaderMatcher(t *testing.T) { func TestHeaderREMatcher(t *testing.T) { for i, tc := range []struct { - match matchHeaderRE + match MatchHeaderRE input http.Header // make sure these are canonical cased (std lib will do that in a real request) expect bool expectRepl map[string]string }{ { - match: matchHeaderRE{"Field": &matchRegexp{Pattern: "foo"}}, + match: MatchHeaderRE{"Field": &matchRegexp{Pattern: "foo"}}, input: http.Header{"Field": []string{"foo"}}, expect: true, }, { - match: matchHeaderRE{"Field": &matchRegexp{Pattern: "$foo^"}}, + match: MatchHeaderRE{"Field": &matchRegexp{Pattern: "$foo^"}}, input: http.Header{"Field": []string{"foobar"}}, expect: false, }, { - match: matchHeaderRE{"Field": &matchRegexp{Pattern: "^foo(.*)$", Name: "name"}}, + match: MatchHeaderRE{"Field": &matchRegexp{Pattern: "^foo(.*)$", Name: "name"}}, input: http.Header{"Field": []string{"foobar"}}, expect: true, expectRepl: map[string]string{"name.1": "bar"}, diff --git a/modules/caddyhttp/reverseproxy/upstream.go b/modules/caddyhttp/reverseproxy/upstream.go index 12178612..1d77a8e1 100755 --- a/modules/caddyhttp/reverseproxy/upstream.go +++ b/modules/caddyhttp/reverseproxy/upstream.go @@ -37,6 +37,8 @@ const ( // TypeBalanceRandom represents the value to use for configuring a load balanced reverse proxy to use random load balancing. TypeBalanceRandom + // TODO: add random with two choices + // msgNoHealthyUpstreams is returned if there are no upstreams that are healthy to proxy a request to msgNoHealthyUpstreams = "No healthy upstreams." diff --git a/modules/caddyhttp/rewrite/rewrite.go b/modules/caddyhttp/rewrite/rewrite.go index b7878a5c..b898b1f9 100644 --- a/modules/caddyhttp/rewrite/rewrite.go +++ b/modules/caddyhttp/rewrite/rewrite.go @@ -18,9 +18,9 @@ func init() { // Rewrite is a middleware which can rewrite HTTP requests. type Rewrite struct { - Method string `json:"method"` - URI string `json:"uri"` - Rehandle bool `json:"rehandle"` + Method string `json:"method,omitempty"` + URI string `json:"uri,omitempty"` + Rehandle bool `json:"rehandle,omitempty"` } func (rewr Rewrite) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error { diff --git a/modules/caddyhttp/routes.go b/modules/caddyhttp/routes.go index 92aa3e87..07e0566c 100644 --- a/modules/caddyhttp/routes.go +++ b/modules/caddyhttp/routes.go @@ -12,12 +12,12 @@ import ( // middlewares, and a responder for handling HTTP // requests. type ServerRoute struct { - Group string `json:"group"` - Matchers map[string]json.RawMessage `json:"match"` - Apply []json.RawMessage `json:"apply"` - Respond json.RawMessage `json:"respond"` + Group string `json:"group,omitempty"` + Matchers map[string]json.RawMessage `json:"match,omitempty"` + Apply []json.RawMessage `json:"apply,omitempty"` + Respond json.RawMessage `json:"respond,omitempty"` - Terminal bool `json:"terminal"` + Terminal bool `json:"terminal,omitempty"` // decoded values matchers []RequestMatcher diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go index dea34fb8..c66fcabb 100644 --- a/modules/caddyhttp/server.go +++ b/modules/caddyhttp/server.go @@ -13,15 +13,15 @@ import ( // Server is an HTTP server. type Server struct { - Listen []string `json:"listen"` - ReadTimeout caddy2.Duration `json:"read_timeout"` - ReadHeaderTimeout caddy2.Duration `json:"read_header_timeout"` - Routes RouteList `json:"routes"` - Errors httpErrorConfig `json:"errors"` - TLSConnPolicies caddytls.ConnectionPolicies `json:"tls_connection_policies"` - DisableAutoHTTPS bool `json:"disable_auto_https"` - DisableAutoHTTPSRedir bool `json:"disable_auto_https_redir"` - MaxRehandles int `json:"max_rehandles"` + Listen []string `json:"listen,omitempty"` + ReadTimeout caddy2.Duration `json:"read_timeout,omitempty"` + ReadHeaderTimeout caddy2.Duration `json:"read_header_timeout,omitempty"` + Routes RouteList `json:"routes,omitempty"` + Errors *httpErrorConfig `json:"errors,omitempty"` + TLSConnPolicies caddytls.ConnectionPolicies `json:"tls_connection_policies,omitempty"` + DisableAutoHTTPS bool `json:"disable_auto_https,omitempty"` + DisableAutoHTTPSRedir bool `json:"disable_auto_https_redir,omitempty"` + MaxRehandles int `json:"max_rehandles,omitempty"` tlsApp *caddytls.TLS } @@ -99,7 +99,7 @@ func (s *Server) executeCompositeRoute(w http.ResponseWriter, r *http.Request, s } type httpErrorConfig struct { - Routes RouteList `json:"routes"` + Routes RouteList `json:"routes,omitempty"` // TODO: some way to configure the logging of errors, probably? standardize // the logging configuration first. }