Address second review findings F1-F3 for 404, public URL and listen host
Independent review Approved — 0 high findings (#2)
Independent review Approved — 0 high findings (#2)
- F1: return the JSON API error shape for unknown paths (404 not_found) - F2: require a non-empty hostname in MEALQUEST_PUBLIC_URL - F3: validate the MEALQUEST_HTTP_ADDR host as an IP address or hostname Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -119,11 +119,16 @@ func (r *reader) listenAddr(name string) string {
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
_, port, err := net.SplitHostPort(v)
|
||||
host, port, err := net.SplitHostPort(v)
|
||||
if err != nil {
|
||||
r.fail(name, "invalid listen address %q (want host:port or :port)", v)
|
||||
return ""
|
||||
}
|
||||
// An empty host listens on all interfaces.
|
||||
if host != "" && net.ParseIP(host) == nil && !validHostname(host) {
|
||||
r.fail(name, "invalid host %q in listen address (want IP address or hostname)", host)
|
||||
return ""
|
||||
}
|
||||
if _, err := strconv.ParseUint(port, 10, 16); err != nil {
|
||||
r.fail(name, "invalid port %q in listen address (want 0-65535)", port)
|
||||
return ""
|
||||
@@ -131,6 +136,25 @@ func (r *reader) listenAddr(name string) string {
|
||||
return v
|
||||
}
|
||||
|
||||
// validHostname reports whether h is a DNS hostname: dot-separated labels of
|
||||
// 1-63 letters, digits and hyphens, not starting or ending with a hyphen.
|
||||
func validHostname(h string) bool {
|
||||
if len(h) > 253 {
|
||||
return false
|
||||
}
|
||||
for _, label := range strings.Split(strings.TrimSuffix(h, "."), ".") {
|
||||
if len(label) < 1 || len(label) > 63 || label[0] == '-' || label[len(label)-1] == '-' {
|
||||
return false
|
||||
}
|
||||
for _, c := range label {
|
||||
if !(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '-') {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *reader) httpURL(name string) *url.URL {
|
||||
v, ok := r.required(name)
|
||||
if !ok {
|
||||
@@ -138,7 +162,7 @@ func (r *reader) httpURL(name string) *url.URL {
|
||||
}
|
||||
// The value is never echoed: it may carry credentials.
|
||||
u, err := url.Parse(v)
|
||||
if err != nil || (u.Scheme != "http" && u.Scheme != "https") || u.Host == "" {
|
||||
if err != nil || (u.Scheme != "http" && u.Scheme != "https") || u.Hostname() == "" {
|
||||
r.fail(name, "invalid URL (want absolute http:// or https:// URL)")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -102,6 +102,43 @@ func TestLoad(t *testing.T) {
|
||||
env: with(map[string]string{EnvHTTPAddr: ":65536"}),
|
||||
badVars: []string{EnvHTTPAddr},
|
||||
},
|
||||
{
|
||||
name: "listen address with IP host",
|
||||
env: with(map[string]string{EnvHTTPAddr: "127.0.0.1:8080"}),
|
||||
},
|
||||
{
|
||||
name: "listen address with IPv6 host",
|
||||
env: with(map[string]string{EnvHTTPAddr: "[::1]:8080"}),
|
||||
},
|
||||
{
|
||||
name: "listen address with hostname",
|
||||
env: with(map[string]string{EnvHTTPAddr: "localhost:8080"}),
|
||||
},
|
||||
{
|
||||
name: "listen host with space",
|
||||
env: with(map[string]string{EnvHTTPAddr: "bad host:8080"}),
|
||||
badVars: []string{EnvHTTPAddr},
|
||||
},
|
||||
{
|
||||
name: "listen host with leading hyphen label",
|
||||
env: with(map[string]string{EnvHTTPAddr: "-bad.example.com:8080"}),
|
||||
badVars: []string{EnvHTTPAddr},
|
||||
},
|
||||
{
|
||||
name: "listen host with empty label",
|
||||
env: with(map[string]string{EnvHTTPAddr: "bad..example.com:8080"}),
|
||||
badVars: []string{EnvHTTPAddr},
|
||||
},
|
||||
{
|
||||
name: "listen host with label over 63 chars",
|
||||
env: with(map[string]string{EnvHTTPAddr: strings.Repeat("a", 64) + ".example.com:8080"}),
|
||||
badVars: []string{EnvHTTPAddr},
|
||||
},
|
||||
{
|
||||
name: "public URL without hostname",
|
||||
env: with(map[string]string{EnvPublicURL: "http://:8080"}),
|
||||
badVars: []string{EnvPublicURL},
|
||||
},
|
||||
{
|
||||
name: "relative public URL",
|
||||
env: with(map[string]string{EnvPublicURL: "meals.example.com"}),
|
||||
|
||||
Reference in New Issue
Block a user