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