mirror of
https://github.com/caddyserver/caddy.git
synced 2024-11-25 09:14:53 +08:00
Improve docs, especially w.r.t. placeholders and template actions
This commit is contained in:
parent
95d944613b
commit
fdabac51a8
5
caddy.go
5
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"
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"`
|
||||
|
||||
|
|
|
@ -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 {
|
||||
// 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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Block a user