Browse Source

Export types and fields necessary to build configs (for config adapters)

Also flag most fields with 'omitempty' for JSON marshaling
master
Matthew Holt 6 years ago
parent
commit
bc00d840e8
  1. 4
      caddy.go
  2. 14
      modules/caddyhttp/caddyhttp.go
  3. 2
      modules/caddyhttp/fileserver/browse.go
  4. 16
      modules/caddyhttp/fileserver/staticfiles.go
  5. 16
      modules/caddyhttp/headers/headers.go
  6. 78
      modules/caddyhttp/matchers.go
  7. 96
      modules/caddyhttp/matchers_test.go
  8. 2
      modules/caddyhttp/reverseproxy/upstream.go
  9. 6
      modules/caddyhttp/rewrite/rewrite.go
  10. 10
      modules/caddyhttp/routes.go
  11. 20
      modules/caddyhttp/server.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.

14
modules/caddyhttp/caddyhttp.go

@ -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

2
modules/caddyhttp/fileserver/browse.go

@ -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
} }

16
modules/caddyhttp/fileserver/staticfiles.go

@ -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
} }

16
modules/caddyhttp/headers/headers.go

@ -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
} }

78
modules/caddyhttp/matchers.go

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

96
modules/caddyhttp/matchers_test.go

@ -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"},

2
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 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."

6
modules/caddyhttp/rewrite/rewrite.go

@ -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 {

10
modules/caddyhttp/routes.go

@ -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

20
modules/caddyhttp/server.go

@ -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…
Cancel
Save