summaryrefslogtreecommitdiff
path: root/caddyconfig/httpcaddyfile/addresses.go
diff options
context:
space:
mode:
authorMatthew Holt <mholt@users.noreply.github.com>2020-01-09 12:35:53 -0700
committerMatthew Holt <mholt@users.noreply.github.com>2020-01-09 12:35:53 -0700
commit8aef859a5510e883a70fb562d5fb83c7585cc301 (patch)
tree58ee9021344145c7433f8e8b497aef07d38f4e3c /caddyconfig/httpcaddyfile/addresses.go
parenta5ebec00419f77bb408f67c360b4a09c5884109d (diff)
caddyfile: Less strict URL parsing; allows placeholders
See https://caddy.community/t/caddy-v2-reusable-snippets/6744/11?u=matt
Diffstat (limited to 'caddyconfig/httpcaddyfile/addresses.go')
-rw-r--r--caddyconfig/httpcaddyfile/addresses.go74
1 files changed, 49 insertions, 25 deletions
diff --git a/caddyconfig/httpcaddyfile/addresses.go b/caddyconfig/httpcaddyfile/addresses.go
index deb27c2..431bb75 100644
--- a/caddyconfig/httpcaddyfile/addresses.go
+++ b/caddyconfig/httpcaddyfile/addresses.go
@@ -17,7 +17,6 @@ package httpcaddyfile
import (
"fmt"
"net"
- "net/url"
"reflect"
"strconv"
"strings"
@@ -209,44 +208,69 @@ type Address struct {
// ParseAddress parses an address string into a structured format with separate
// scheme, host, port, and path portions, as well as the original input string.
func ParseAddress(str string) (Address, error) {
- httpPort, httpsPort := strconv.Itoa(certmagic.HTTPPort), strconv.Itoa(certmagic.HTTPSPort)
-
- input := str
-
- // Split input into components (prepend with // to force host portion by default)
- if !strings.Contains(str, "//") && !strings.HasPrefix(str, "/") {
- str = "//" + str
+ const maxLen = 4096
+ if len(str) > maxLen {
+ str = str[:maxLen]
}
-
- u, err := url.Parse(str)
- if err != nil {
- return Address{}, err
+ remaining := strings.TrimSpace(str)
+ a := Address{Original: remaining}
+
+ // extract scheme
+ splitScheme := strings.SplitN(remaining, "://", 2)
+ switch len(splitScheme) {
+ case 0:
+ return a, nil
+ case 1:
+ remaining = splitScheme[0]
+ case 2:
+ a.Scheme = splitScheme[0]
+ remaining = splitScheme[1]
}
- // separate host and port
- host, port, err := net.SplitHostPort(u.Host)
- if err != nil {
- host, port, err = net.SplitHostPort(u.Host + ":")
+ // extract host and port
+ hostSplit := strings.SplitN(remaining, "/", 2)
+ if len(hostSplit) > 0 {
+ host, port, err := net.SplitHostPort(hostSplit[0])
if err != nil {
- host = u.Host
+ host, port, err = net.SplitHostPort(hostSplit[0] + ":")
+ if err != nil {
+ host = hostSplit[0]
+ }
}
+ a.Host = host
+ a.Port = port
+ }
+ if len(hostSplit) == 2 {
+ // all that remains is the path
+ a.Path = "/" + hostSplit[1]
}
+ httpPort, httpsPort := strconv.Itoa(certmagic.HTTPPort), strconv.Itoa(certmagic.HTTPSPort)
+
// see if we can set port based off scheme
- if port == "" {
- if u.Scheme == "http" {
- port = httpPort
- } else if u.Scheme == "https" {
- port = httpsPort
+ if a.Port == "" {
+ if a.Scheme == "http" {
+ a.Port = httpPort
+ } else if a.Scheme == "https" {
+ a.Port = httpsPort
+ }
+ }
+
+ // make sure port is valid
+ if a.Port != "" {
+ if portNum, err := strconv.Atoi(a.Port); err != nil {
+ return Address{}, fmt.Errorf("invalid port '%s': %v", a.Port, err)
+ } else if portNum < 0 || portNum > 65535 {
+ return Address{}, fmt.Errorf("port %d is out of range", portNum)
}
}
// error if scheme and port combination violate convention
- if (u.Scheme == "http" && port == httpsPort) || (u.Scheme == "https" && port == httpPort) {
- return Address{}, fmt.Errorf("[%s] scheme and port violate convention", input)
+ if (a.Scheme == "http" && a.Port == httpsPort) || (a.Scheme == "https" && a.Port == httpPort) {
+ return Address{}, fmt.Errorf("[%s] scheme and port violate convention", str)
}
- return Address{Original: input, Scheme: u.Scheme, Host: host, Port: port, Path: u.Path}, err
+ return a, nil
}
// TODO: which of the methods on Address are even used?