diff options
author | Matt Holt <mholt@users.noreply.github.com> | 2019-08-21 11:28:03 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-08-21 11:28:03 -0600 |
commit | 0544f0266a11874efb305a46db762248e64bc62d (patch) | |
tree | 3e75e6f59047bb967c52915e1e75aee6ad67c0ea /modules/caddyhttp/caddyhttp.go | |
parent | 42f75a4ca94ef3fb5e15a74e5dc9ef8b4f1f0b39 (diff) | |
parent | b2aa679c33f63ebec5bc1a21bca01f345dffebdd (diff) |
Merge pull request #2699 from caddyserver/cfadapter
v2: Implement config adapters and WIP Caddyfile adapter
Diffstat (limited to 'modules/caddyhttp/caddyhttp.go')
-rw-r--r-- | modules/caddyhttp/caddyhttp.go | 105 |
1 files changed, 96 insertions, 9 deletions
diff --git a/modules/caddyhttp/caddyhttp.go b/modules/caddyhttp/caddyhttp.go index 467b40f..b4b1ec6 100644 --- a/modules/caddyhttp/caddyhttp.go +++ b/modules/caddyhttp/caddyhttp.go @@ -15,9 +15,12 @@ package caddyhttp import ( + "bytes" "context" "crypto/tls" + "encoding/json" "fmt" + "io" "log" weakrand "math/rand" "net" @@ -34,10 +37,7 @@ import ( func init() { weakrand.Seed(time.Now().UnixNano()) - err := caddy.RegisterModule(caddy.Module{ - Name: "http", - New: func() interface{} { return new(App) }, - }) + err := caddy.RegisterModule(App{}) if err != nil { log.Fatal(err) } @@ -55,6 +55,14 @@ type App struct { ctx caddy.Context } +// CaddyModule returns the Caddy module information. +func (App) CaddyModule() caddy.ModuleInfo { + return caddy.ModuleInfo{ + Name: "http", + New: func() caddy.Module { return new(App) }, + } +} + // Provision sets up the app. func (app *App) Provision(ctx caddy.Context) error { app.ctx = ctx @@ -224,7 +232,7 @@ func (app *App) automaticHTTPS() error { // find all qualifying domain names, de-duplicated domainSet := make(map[string]struct{}) for _, route := range srv.Routes { - for _, matcherSet := range route.matcherSets { + for _, matcherSet := range route.MatcherSets { for _, m := range matcherSet { if hm, ok := m.(*MatchHost); ok { for _, d := range *hm { @@ -244,6 +252,14 @@ func (app *App) automaticHTTPS() error { for d := range domainSet { domains = append(domains, d) if !srv.AutoHTTPS.Skipped(d, srv.AutoHTTPS.SkipCerts) { + // if a certificate for this name is already loaded, + // don't obtain another one for it, unless we are + // supposed to ignore loaded certificates + if !srv.AutoHTTPS.IgnoreLoadedCerts && + len(tlsApp.CertificatesWithSAN(d)) > 0 { + log.Printf("[INFO][%s] Skipping automatic certificate management because a certificate with that SAN is already loaded", d) + continue + } domainsForCerts = append(domainsForCerts, d) } } @@ -319,16 +335,16 @@ func (app *App) automaticHTTPS() error { } redirTo += "{http.request.uri}" - redirRoutes = append(redirRoutes, ServerRoute{ - matcherSets: []MatcherSet{ + redirRoutes = append(redirRoutes, Route{ + MatcherSets: []MatcherSet{ { MatchProtocol("http"), MatchHost(domains), }, }, - handlers: []MiddlewareHandler{ + Handlers: []MiddlewareHandler{ StaticResponse{ - StatusCode: weakString(strconv.Itoa(http.StatusTemporaryRedirect)), // TODO: use permanent redirect instead + StatusCode: WeakString(strconv.Itoa(http.StatusTemporaryRedirect)), // TODO: use permanent redirect instead Headers: http.Header{ "Location": []string{redirTo}, "Connection": []string{"close"}, @@ -431,6 +447,77 @@ type MiddlewareHandler interface { // emptyHandler is used as a no-op handler. var emptyHandler HandlerFunc = func(http.ResponseWriter, *http.Request) error { return nil } +// WeakString is a type that unmarshals any JSON value +// as a string literal, with the following exceptions: +// 1) actual string values are decoded as strings, and +// 2) null is decoded as empty string +// and provides methods for getting the value as various +// primitive types. However, using this type removes any +// type safety as far as deserializing JSON is concerned. +type WeakString string + +// UnmarshalJSON satisfies json.Unmarshaler according to +// this type's documentation. +func (ws *WeakString) UnmarshalJSON(b []byte) error { + if len(b) == 0 { + return io.EOF + } + if b[0] == byte('"') && b[len(b)-1] == byte('"') { + var s string + err := json.Unmarshal(b, &s) + if err != nil { + return err + } + *ws = WeakString(s) + return nil + } + if bytes.Equal(b, []byte("null")) { + return nil + } + *ws = WeakString(b) + return nil +} + +// MarshalJSON marshals was a boolean if true or false, +// a number if an integer, or a string otherwise. +func (ws WeakString) MarshalJSON() ([]byte, error) { + if ws == "true" { + return []byte("true"), nil + } + if ws == "false" { + return []byte("false"), nil + } + if num, err := strconv.Atoi(string(ws)); err == nil { + return json.Marshal(num) + } + return json.Marshal(string(ws)) +} + +// Int returns ws as an integer. If ws is not an +// integer, 0 is returned. +func (ws WeakString) Int() int { + num, _ := strconv.Atoi(string(ws)) + return num +} + +// Float64 returns ws as a float64. If ws is not a +// float value, the zero value is returned. +func (ws WeakString) Float64() float64 { + num, _ := strconv.ParseFloat(string(ws), 64) + return num +} + +// Bool returns ws as a boolean. If ws is not a +// boolean, false is returned. +func (ws WeakString) Bool() bool { + return string(ws) == "true" +} + +// String returns ws as a string. +func (ws WeakString) String() string { + return string(ws) +} + const ( // DefaultHTTPPort is the default port for HTTP. DefaultHTTPPort = 80 |