diff --git a/rule/url.go b/rule/url.go index 592ea20..ef8ec8e 100644 --- a/rule/url.go +++ b/rule/url.go @@ -13,7 +13,13 @@ func URL(ctx context.Context, v string) error { v = v[:i] } - if value, err := url.ParseRequestURI(v); err != nil || value.Scheme == "" { + value, err := url.ParseRequestURI(v) + if err != nil || value.Scheme == "" { + return NewError(NameURL) + } + + // http(s) URLs without a host are not usable destinations (e.g. "http://", "https:") + if (value.Scheme == "http" || value.Scheme == "https") && value.Host == "" { return NewError(NameURL) } diff --git a/rule/url_test.go b/rule/url_test.go new file mode 100644 index 0000000..e453d78 --- /dev/null +++ b/rule/url_test.go @@ -0,0 +1,31 @@ +package rule_test + +import ( + "context" + "testing" + + "github.com/foomo/fender/rule" +) + +func TestURLRequiresHostForHTTP(t *testing.T) { + t.Parallel() + + cases := map[string]bool{ + "http://example.com": true, + "https://example.com": true, + "http://example.com/": true, + "ftp://example.com": true, + "http://": false, + "https:": false, + "http:///": false, + "": false, + } + + for input, wantOK := range cases { + err := rule.URL(context.Background(), input) + gotOK := err == nil + if gotOK != wantOK { + t.Errorf("URL(%q) ok=%v want %v (err=%v)", input, gotOK, wantOK, err) + } + } +}