summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--caddy.go5
-rw-r--r--modules.go8
-rw-r--r--modules/caddyhttp/caddyhttp.go42
-rw-r--r--modules/caddyhttp/fileserver/matcher.go12
-rw-r--r--modules/caddyhttp/matchers.go45
-rw-r--r--modules/caddyhttp/reverseproxy/reverseproxy.go25
-rw-r--r--modules/caddyhttp/server.go43
-rw-r--r--modules/caddyhttp/templates/templates.go148
8 files changed, 265 insertions, 63 deletions
diff --git a/caddy.go b/caddy.go
index cde42b1..5477267 100644
--- a/caddy.go
+++ b/caddy.go
@@ -506,7 +506,7 @@ func goModule(mod *debug.Module) *debug.Module {
// TODO: track related Go issue: https://github.com/golang/go/issues/29228
// once that issue is fixed, we should just be able to use bi.Main... hopefully.
for _, dep := range bi.Deps {
- if dep.Path == "github.com/caddyserver/caddy/v2" {
+ if dep.Path == ImportPath {
return dep
}
}
@@ -543,3 +543,6 @@ var (
// path, for converting /id/ paths to /config/ paths.
rawCfgIndex map[string]string
)
+
+// ImportPath is the package import path for Caddy core.
+const ImportPath = "github.com/caddyserver/caddy/v2"
diff --git a/modules.go b/modules.go
index b036bea..46fdd3b 100644
--- a/modules.go
+++ b/modules.go
@@ -75,16 +75,16 @@ type ModuleInfo struct {
// label is the module name, and the labels before that constitute
// the namespace (or scope).
//
-// Thus, a module ID has the form: <namespace>.<id>
+// Thus, a module ID has the form: <namespace>.<name>
//
// An ID with no dot has the empty namespace, which is appropriate
// for app modules (these are "top-level" modules that Caddy core
// loads and runs).
//
-// Module IDs should be lowercase and use underscore (_) instead of
+// Module IDs should be lowercase and use underscores (_) instead of
// spaces.
//
-// Example valid names:
+// Examples of valid IDs:
// - http
// - http.handlers.file_server
// - caddy.logging.encoders.json
@@ -92,7 +92,7 @@ type ModuleID string
// Namespace returns the namespace (or scope) portion of a module ID,
// which is all but the last label of the ID. If the ID has only one
-// label, then
+// label, then the namespace is empty.
func (id ModuleID) Namespace() string {
lastDot := strings.LastIndex(string(id), ".")
if lastDot < 0 {
diff --git a/modules/caddyhttp/caddyhttp.go b/modules/caddyhttp/caddyhttp.go
index d3be288..38e9a65 100644
--- a/modules/caddyhttp/caddyhttp.go
+++ b/modules/caddyhttp/caddyhttp.go
@@ -44,7 +44,47 @@ func init() {
}
}
-// App is a robust, flexible HTTP server for Caddy.
+// App is a robust, production-ready HTTP server.
+//
+// HTTPS is enabled by default if host matchers with qualifying names are used
+// in any of routes; certificates are automatically provisioned and renewed.
+// Additionally, automatic HTTPS will also enable HTTPS for servers that listen
+// only on the HTTPS port but which do not have any TLS connection policies
+// defined by adding a good, default TLS connection policy.
+//
+// In HTTP routes, additional placeholders are available:
+//
+// Placeholder | Description
+// ------------|---------------
+// `{http.request.cookie.*}` | HTTP request cookie
+// `{http.request.header.*}` | Specific request header field
+// `{http.request.host.labels.*}` | Request host labels (0-based from right); e.g. for foo.example.com: 0=com, 1=example, 2=foo
+// `{http.request.host}` | The host part of the request's Host header
+// `{http.request.hostport}` | The host and port from the request's Host header
+// `{http.request.method}` | The request method
+// `{http.request.orig.method}` | The request's original method
+// `{http.request.orig.path.dir}` | The request's original directory
+// `{http.request.orig.path.file}` | The request's original filename
+// `{http.request.orig.uri.path}` | The request's original path
+// `{http.request.orig.uri.query_string}` | The request's original full query string (with `?`)
+// `{http.request.orig.uri.query}` | The request's original query string (without `?`)
+// `{http.request.orig.uri}` | The request's original URI
+// `{http.request.port}` | The port part of the request's Host header
+// `{http.request.proto}` | The protocol of the request
+// `{http.request.remote.host}` | The host part of the remote client's address
+// `{http.request.remote.port}` | The port part of the remote client's address
+// `{http.request.remote}` | The address of the remote client
+// `{http.request.scheme}` | The request scheme
+// `{http.request.uri.path.*}` | Parts of the path, split by `/` (0-based from left)
+// `{http.request.uri.path.dir}` | The directory, excluding leaf filename
+// `{http.request.uri.path.file}` | The filename of the path, excluding directory
+// `{http.request.uri.path}` | The path component of the request URI
+// `{http.request.uri.query_string}` | The full query string (with `?`)
+// `{http.request.uri.query.*}` | Individual query string value
+// `{http.request.uri.query}` | The query string (without `?`)
+// `{http.request.uri}` | The full request URI
+// `{http.response.header.*}` | Specific response header field
+// `{http.vars.*}` | Custom variables in the HTTP handler chain
type App struct {
// HTTPPort specifies the port to use for HTTP (as opposed to HTTPS),
// which is used when setting up HTTP->HTTPS redirects or ACME HTTP
diff --git a/modules/caddyhttp/fileserver/matcher.go b/modules/caddyhttp/fileserver/matcher.go
index 6c1e880..c119865 100644
--- a/modules/caddyhttp/fileserver/matcher.go
+++ b/modules/caddyhttp/fileserver/matcher.go
@@ -33,10 +33,20 @@ func init() {
// MatchFile is an HTTP request matcher that can match
// requests based upon file existence.
+//
+// Upon matching, two new placeholders will be made
+// available:
+//
+// - `{http.matchers.file.relative}` The root-relative
+// path of the file. This is often useful when rewriting
+// requests.
+// - `{http.matchers.file.absolute}` The absolute path
+// of the matched file.
type MatchFile struct {
// The root directory, used for creating absolute
// file paths, and required when working with
- // relative paths; if not specified, the current
+ // relative paths; if not specified, `{http.vars.root}`
+ // will be used, if set; otherwise, the current
// directory is assumed. Accepts placeholders.
Root string `json:"root,omitempty"`
diff --git a/modules/caddyhttp/matchers.go b/modules/caddyhttp/matchers.go
index 170dbe7..6c44108 100644
--- a/modules/caddyhttp/matchers.go
+++ b/modules/caddyhttp/matchers.go
@@ -40,6 +40,12 @@ type (
MatchPath []string
// MatchPathRE matches requests by a regular expression on the URI's path.
+ //
+ // Upon a match, it adds placeholders to the request: `{http.regexp.name.capture_group}`
+ // where `name` is the regular expression's name, and `capture_group` is either
+ // the named or positional capture group from the expression itself. If no name
+ // is given, then the placeholder omits the name: `{http.regexp.capture_group}`
+ // (potentially leading to collisions).
MatchPathRE struct{ MatchRegexp }
// MatchMethod matches requests by the method.
@@ -52,6 +58,12 @@ type (
MatchHeader http.Header
// MatchHeaderRE matches requests by a regular expression on header fields.
+ //
+ // Upon a match, it adds placeholders to the request: `{http.regexp.name.capture_group}`
+ // where `name` is the regular expression's name, and `capture_group` is either
+ // the named or positional capture group from the expression itself. If no name
+ // is given, then the placeholder omits the name: `{http.regexp.capture_group}`
+ // (potentially leading to collisions).
MatchHeaderRE map[string]*MatchRegexp
// MatchProtocol matches requests by protocol.
@@ -65,6 +77,8 @@ type (
}
// MatchNegate matches requests by negating its matchers' results.
+ // To use, simply specify a set of matchers like you normally would;
+ // the only difference is that their result will be negated.
MatchNegate struct {
MatchersRaw caddy.ModuleMap `json:"-" caddy:"namespace=http.matchers"`
@@ -624,11 +638,26 @@ func (m MatchStarlarkExpr) Match(r *http.Request) bool {
}
// MatchRegexp is an embeddable type for matching
-// using regular expressions.
+// using regular expressions. It adds placeholders
+// to the request's replacer.
type MatchRegexp struct {
- Name string `json:"name,omitempty"`
- Pattern string `json:"pattern"`
+ // A unique name for this regular expression. Optional,
+ // but useful to prevent overwriting captures from other
+ // regexp matchers.
+ Name string `json:"name,omitempty"`
+
+ // The regular expression to evaluate, in RE2 syntax,
+ // which is the same general syntax used by Go, Perl,
+ // and Python. For details, see
+ // [Go's regexp package](https://golang.org/pkg/regexp/).
+ // Captures are accessible via placeholders. Unnamed
+ // capture groups are exposed as their numeric, 1-based
+ // index, while named capture groups are available by
+ // the capture group name.
+ Pattern string `json:"pattern"`
+
compiled *regexp.Regexp
+ phPrefix string
}
// Provision compiles the regular expression.
@@ -638,6 +667,10 @@ func (mre *MatchRegexp) Provision(caddy.Context) error {
return fmt.Errorf("compiling matcher regexp %s: %v", mre.Pattern, err)
}
mre.compiled = re
+ mre.phPrefix = regexpPlaceholderPrefix
+ if mre.Name != "" {
+ mre.phPrefix += "." + mre.Name
+ }
return nil
}
@@ -661,14 +694,14 @@ func (mre *MatchRegexp) Match(input string, repl *caddy.Replacer) bool {
// save all capture groups, first by index
for i, match := range matches {
- key := fmt.Sprintf("http.regexp.%s.%d", mre.Name, i)
+ key := fmt.Sprintf("%s.%d", mre.phPrefix, i)
repl.Set(key, match)
}
// then by name
for i, name := range mre.compiled.SubexpNames() {
if i != 0 && name != "" {
- key := fmt.Sprintf("http.regexp.%s.%s", mre.Name, name)
+ key := fmt.Sprintf("%s.%s", mre.phPrefix, name)
repl.Set(key, matches[i])
}
}
@@ -752,6 +785,8 @@ func (rm ResponseMatcher) matchHeaders(hdr http.Header) bool {
var wordRE = regexp.MustCompile(`\w+`)
+const regexpPlaceholderPrefix = "http.regexp"
+
// Interface guards
var (
_ RequestMatcher = (*MatchHost)(nil)
diff --git a/modules/caddyhttp/reverseproxy/reverseproxy.go b/modules/caddyhttp/reverseproxy/reverseproxy.go
index 238e86f..d0c4833 100644
--- a/modules/caddyhttp/reverseproxy/reverseproxy.go
+++ b/modules/caddyhttp/reverseproxy/reverseproxy.go
@@ -41,24 +41,19 @@ func init() {
}
// Handler implements a highly configurable and production-ready reverse proxy.
+//
// Upon proxying, this module sets the following placeholders (which can be used
// both within and after this handler):
//
-// {http.reverse_proxy.upstream.address}
-// The full address to the upstream as given in the config
-// {http.reverse_proxy.upstream.hostport}
-// The host:port of the upstream
-// {http.reverse_proxy.upstream.host}
-// The host of the upstream
-// {http.reverse_proxy.upstream.port}
-// The port of the upstream
-// {http.reverse_proxy.upstream.requests}
-// The approximate current number of requests to the upstream
-// {http.reverse_proxy.upstream.max_requests}
-// The maximum approximate number of requests allowed to the upstream
-// {http.reverse_proxy.upstream.fails}
-// The number of recent failed requests to the upstream
-//
+// Placeholder | Description
+// ------------|-------------
+// `{http.reverse_proxy.upstream.address}` | The full address to the upstream as given in the config
+// `{http.reverse_proxy.upstream.hostport}` | The host:port of the upstream
+// `{http.reverse_proxy.upstream.host}` | The host of the upstream
+// `{http.reverse_proxy.upstream.port}` | The port of the upstream
+// `{http.reverse_proxy.upstream.requests}` | The approximate current number of requests to the upstream
+// `{http.reverse_proxy.upstream.max_requests}` | The maximum approximate number of requests allowed to the upstream
+// `{http.reverse_proxy.upstream.fails}` | The number of recent failed requests to the upstream
type Handler struct {
// Configures the method of transport for the proxy. A transport
// is what performs the actual "round trip" to the backend.
diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go
index 0c30139..c333991 100644
--- a/modules/caddyhttp/server.go
+++ b/modules/caddyhttp/server.go
@@ -33,39 +33,9 @@ import (
// Server describes an HTTP server.
type Server struct {
- // Socket interfaces to which to bind listeners. Caddy network
- // addresses have the following form:
- //
- // network/address
- //
- // The network part is anything that [Go's `net` package](https://golang.org/pkg/net/)
- // recognizes, and is optional. The default network is `tcp`. If
- // a network is specified, a single forward slash `/` is used to
- // separate the network and address portions.
- //
- // The address part may be any of these forms:
- //
- // - `host`
- // - `host:port`
- // - `:port`
- // - `/path/to/unix/socket`
- //
- // The host may be any hostname, resolvable domain name, or IP address.
- // The port may be a single value (`:8080`) or a range (`:8080-8085`).
- // A port range will be multiplied into singular addresses. Not all
- // config parameters accept port ranges, but Listen does.
- //
- // Valid examples:
- //
- // :8080
- // 127.0.0.1:8080
- // localhost:8080
- // localhost:8080-8085
- // tcp/localhost:8080
- // tcp/localhost:8080-8085
- // udp/localhost:9005
- // unix//path/to/socket
- //
+ // Socket addresses to which to bind listeners. Accepts
+ // [network addresses](/docs/conventions#network-addresses)
+ // that may include port ranges.
Listen []string `json:"listen,omitempty"`
// How long to allow a read from a client's upload. Setting this
@@ -105,12 +75,15 @@ type Server struct {
// The error routes work exactly like the normal routes.
Errors *HTTPErrorConfig `json:"errors,omitempty"`
- // How to handle TLS connections.
+ // How to handle TLS connections. At least one policy is
+ // required to enable HTTPS on this server if automatic
+ // HTTPS is disabled or does not apply.
TLSConnPolicies caddytls.ConnectionPolicies `json:"tls_connection_policies,omitempty"`
// AutoHTTPS configures or disables automatic HTTPS within this server.
// HTTPS is enabled automatically and by default when qualifying names
- // are present in a Host matcher.
+ // are present in a Host matcher and/or when the server is listening
+ // only on the HTTPS port.
AutoHTTPS *AutoHTTPSConfig `json:"automatic_https,omitempty"`
// MaxRehandles is the maximum number of times to allow a
diff --git a/modules/caddyhttp/templates/templates.go b/modules/caddyhttp/templates/templates.go
index d01b447..adf9844 100644
--- a/modules/caddyhttp/templates/templates.go
+++ b/modules/caddyhttp/templates/templates.go
@@ -29,7 +29,153 @@ func init() {
caddy.RegisterModule(Templates{})
}
-// Templates is a middleware which execute response bodies as templates.
+// Templates is a middleware which executes response bodies as Go templates.
+// The syntax is documented in the Go standard library's
+// [text/template package](https://golang.org/pkg/text/template/).
+//
+// [All Sprig functions](https://masterminds.github.io/sprig/) are supported.
+//
+// In addition to the standard functions and Sprig functions, Caddy adds
+// extra functions and data that are available to a template:
+//
+// ##### **`.Args`**
+//
+// Access arguments passed to this page/context, for example as the result of a `include`.
+//
+// ```
+// {{.Args 0}} // first argument
+// ```
+//
+// ##### `.Cookie`
+//
+// Gets the value of a cookie by name.
+//
+// ```
+// {{.Cookie "cookiename"}}
+// ```
+//
+// ##### `.Host`
+//
+// Returns the hostname portion (no port) of the Host header of the HTTP request.
+//
+// ```
+// {{.Host}}
+// ```
+//
+// ##### `httpInclude`
+//
+// Includes the contents of another file by making a virtual HTTP request (also known as a sub-request). The URI path must exist on the same virtual server because the request does not use sockets; instead, the request is crafted in memory and the handler is invoked directly for increased efficiency.
+//
+// ```
+// {{httpInclude "/foo/bar?q=val"}}
+// ```
+//
+// ##### `include`
+//
+// Includes the contents of another file. Optionally can pass key-value pairs as arguments to be accessed by the included file.
+//
+// ```
+// {{include "path/to/file.html"}} // no arguments
+// {{include "path/to/file.html" "arg1" 2 "value 3"}} // with arguments
+// ```
+//
+// ##### `listFiles`
+//
+// Returns a list of the files in the given directory, which is relative to the template context's file root.
+//
+// ```
+// {{listFiles "/mydir"}}
+// ```
+//
+// ##### `markdown`
+//
+// Renders the given Markdown text as HTML.
+//
+// ```
+// {{markdown "My _markdown_ text"}}
+// ```
+//
+// ##### `.RemoteIP`
+//
+// Returns the client's IP address.
+//
+// ```
+// {{.RemoteIP}}
+// ```
+//
+// ##### `.RespHeader.Add`
+//
+// Adds a header field to the HTTP response.
+//
+// ```
+// {{.RespHeader.Add "Field-Name" "val"}}
+// ```
+//
+// ##### `.RespHeader.Del`
+//
+// Deletes a header field on the HTTP response.
+//
+// ```
+// {{.RespHeader.Del "Field-Name"}}
+// ```
+//
+// ##### `.RespHeader.Set`
+//
+// Sets a header field on the HTTP response, replacing any existing value.
+//
+// ```
+// {{.RespHeader.Set "Field-Name" "val"}}
+// ```
+//
+// ##### `splitFrontMatter`
+//
+// Splits front matter out from the body. Front matter is metadata that appears at the very beginning of a file or string. Front matter can be in YAML, TOML, or JSON formats:
+//
+// **TOML** front matter starts and ends with `+++`:
+//
+// ```
+// +++
+// template = "blog"
+// title = "Blog Homepage"
+// sitename = "A Caddy site"
+// +++
+// ```
+//
+// **YAML** is surrounded by `---`:
+//
+// ```
+// ---
+// template: blog
+// title: Blog Homepage
+// sitename: A Caddy site
+// ---
+// ```
+//
+//
+// **JSON** is simply `{` and `}`:
+//
+// ```
+// {
+// "template": "blog",
+// "title": "Blog Homepage",
+// "sitename": "A Caddy site"
+// }
+// ```
+//
+// The resulting front matter will be made available like so:
+//
+// - `.Meta` to access the metadata fields, for example: `{{$parsed.Meta.title}}`
+// - `.Body` to access the body after the front matter, for example: `{{markdown $parsed.Body}}`
+//
+//
+// ##### `stripHTML`
+//
+// Removes HTML from a string.
+//
+// ```
+// {{stripHTML "Shows <b>only</b> text content"}}
+// ```
+//
type Templates struct {
// The root path from which to load files. Required if template functions
// accessing the file system are used (such as include). Default is