mirror of https://github.com/caddyserver/caddy.git
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
4
caddy.go
4
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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
)
|
||||
|
|
|
@ -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<myparam>.*)/baz$", Name: "name"}},
|
||||
match: MatchPathRE{matchRegexp{Pattern: "^/foo/(?P<myparam>.*)/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"},
|
||||
|
|
|
@ -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."
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue