summaryrefslogtreecommitdiff
path: root/caddyconfig/httploader.go
diff options
context:
space:
mode:
Diffstat (limited to 'caddyconfig/httploader.go')
-rw-r--r--caddyconfig/httploader.go151
1 files changed, 151 insertions, 0 deletions
diff --git a/caddyconfig/httploader.go b/caddyconfig/httploader.go
new file mode 100644
index 0000000..aabd103
--- /dev/null
+++ b/caddyconfig/httploader.go
@@ -0,0 +1,151 @@
+package caddyconfig
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "time"
+
+ "github.com/caddyserver/caddy/v2"
+)
+
+func init() {
+ caddy.RegisterModule(HTTPLoader{})
+}
+
+// HTTPLoader can load Caddy configs over HTTP(S). It can adapt the config
+// based on the Content-Type header of the HTTP response.
+type HTTPLoader struct {
+ // The method for the request. Default: GET
+ Method string `json:"method,omitempty"`
+
+ // The URL of the request.
+ URL string `json:"url,omitempty"`
+
+ // HTTP headers to add to the request.
+ Headers http.Header `json:"header,omitempty"`
+
+ // Maximum time allowed for a complete connection and request.
+ Timeout caddy.Duration `json:"timeout,omitempty"`
+
+ TLS *struct {
+ // Present this instance's managed remote identity credentials to the server.
+ UseServerIdentity bool `json:"use_server_identity,omitempty"`
+
+ // PEM-encoded client certificate filename to present to the server.
+ ClientCertificateFile string `json:"client_certificate_file,omitempty"`
+
+ // PEM-encoded key to use with the client certificate.
+ ClientCertificateKeyFile string `json:"client_certificate_key_file,omitempty"`
+
+ // List of PEM-encoded CA certificate files to add to the same trust
+ // store as RootCAPool (or root_ca_pool in the JSON).
+ RootCAPEMFiles []string `json:"root_ca_pem_files,omitempty"`
+ } `json:"tls,omitempty"`
+}
+
+// CaddyModule returns the Caddy module information.
+func (HTTPLoader) CaddyModule() caddy.ModuleInfo {
+ return caddy.ModuleInfo{
+ ID: "caddy.config_loaders.http",
+ New: func() caddy.Module { return new(HTTPLoader) },
+ }
+}
+
+// LoadConfig loads a Caddy config.
+func (hl HTTPLoader) LoadConfig(ctx caddy.Context) ([]byte, error) {
+ client, err := hl.makeClient(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ method := hl.Method
+ if method == "" {
+ method = http.MethodGet
+ }
+
+ req, err := http.NewRequest(method, hl.URL, nil)
+ if err != nil {
+ return nil, err
+ }
+ req.Header = hl.Headers
+
+ resp, err := client.Do(req)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+ if resp.StatusCode >= 400 {
+ return nil, fmt.Errorf("server responded with HTTP %d", resp.StatusCode)
+ }
+
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+
+ result, warnings, err := adaptByContentType(resp.Header.Get("Content-Type"), body)
+ if err != nil {
+ return nil, err
+ }
+ for _, warn := range warnings {
+ ctx.Logger(hl).Warn(warn.String())
+ }
+
+ return result, nil
+}
+
+func (hl HTTPLoader) makeClient(ctx caddy.Context) (*http.Client, error) {
+ client := &http.Client{
+ Timeout: time.Duration(hl.Timeout),
+ }
+
+ if hl.TLS != nil {
+ var tlsConfig *tls.Config
+
+ // client authentication
+ if hl.TLS.UseServerIdentity {
+ certs, err := ctx.IdentityCredentials(ctx.Logger(hl))
+ if err != nil {
+ return nil, fmt.Errorf("getting server identity credentials: %v", err)
+ }
+ if tlsConfig == nil {
+ tlsConfig = new(tls.Config)
+ }
+ tlsConfig.Certificates = certs
+ } else if hl.TLS.ClientCertificateFile != "" && hl.TLS.ClientCertificateKeyFile != "" {
+ cert, err := tls.LoadX509KeyPair(hl.TLS.ClientCertificateFile, hl.TLS.ClientCertificateKeyFile)
+ if err != nil {
+ return nil, err
+ }
+ if tlsConfig == nil {
+ tlsConfig = new(tls.Config)
+ }
+ tlsConfig.Certificates = []tls.Certificate{cert}
+ }
+
+ // trusted server certs
+ if len(hl.TLS.RootCAPEMFiles) > 0 {
+ rootPool := x509.NewCertPool()
+ for _, pemFile := range hl.TLS.RootCAPEMFiles {
+ pemData, err := ioutil.ReadFile(pemFile)
+ if err != nil {
+ return nil, fmt.Errorf("failed reading ca cert: %v", err)
+ }
+ rootPool.AppendCertsFromPEM(pemData)
+ }
+ if tlsConfig == nil {
+ tlsConfig = new(tls.Config)
+ }
+ tlsConfig.RootCAs = rootPool
+ }
+
+ client.Transport = &http.Transport{TLSClientConfig: tlsConfig}
+ }
+
+ return client, nil
+}
+
+var _ caddy.ConfigLoader = (*HTTPLoader)(nil)