2021-02-18 01:09:37 +00:00
|
|
|
package gemini
|
|
|
|
|
|
|
|
import (
|
2021-02-20 20:49:07 +00:00
|
|
|
"context"
|
2021-02-18 01:09:37 +00:00
|
|
|
"net/url"
|
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
|
|
|
type nopHandler struct{}
|
|
|
|
|
2021-02-24 01:40:22 +00:00
|
|
|
func (*nopHandler) ServeGemini(context.Context, *ResponseWriter, *Request) {}
|
2021-02-18 01:09:37 +00:00
|
|
|
|
|
|
|
func TestServeMuxMatch(t *testing.T) {
|
|
|
|
type Match struct {
|
|
|
|
URL string
|
|
|
|
Ok bool
|
|
|
|
}
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
Pattern string
|
|
|
|
Matches []Match
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
// scheme: gemini, hostname: *, path: /*
|
|
|
|
Pattern: "/",
|
|
|
|
Matches: []Match{
|
|
|
|
{"gemini://example.com/path", true},
|
|
|
|
{"gemini://example.com/", true},
|
|
|
|
{"gemini://example.com/path.gmi", true},
|
|
|
|
{"gemini://example.com/path/", true},
|
|
|
|
{"gemini://example.org/path", true},
|
|
|
|
{"http://example.com/path", false},
|
|
|
|
{"http://example.org/path", false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// scheme: gemini, hostname: *, path: /path
|
|
|
|
Pattern: "/path",
|
|
|
|
Matches: []Match{
|
|
|
|
{"gemini://example.com/path", true},
|
|
|
|
{"gemini://example.com/", false},
|
|
|
|
{"gemini://example.com/path.gmi", false},
|
|
|
|
{"gemini://example.com/path/", false},
|
|
|
|
{"gemini://example.org/path", true},
|
|
|
|
{"http://example.com/path", false},
|
|
|
|
{"http://example.org/path", false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// scheme: gemini, hostname: *, path: /subtree/*
|
|
|
|
Pattern: "/subtree/",
|
|
|
|
Matches: []Match{
|
|
|
|
{"gemini://example.com/subtree/", true},
|
|
|
|
{"gemini://example.com/subtree/nested/", true},
|
|
|
|
{"gemini://example.com/subtree/nested/file", true},
|
|
|
|
{"gemini://example.org/subtree/", true},
|
|
|
|
{"gemini://example.org/subtree/nested/", true},
|
|
|
|
{"gemini://example.org/subtree/nested/file", true},
|
|
|
|
{"gemini://example.com/subtree", false},
|
|
|
|
{"gemini://www.example.com/subtree/", true},
|
|
|
|
{"http://example.com/subtree/", false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// scheme: gemini, hostname: example.com, path: /*
|
|
|
|
Pattern: "example.com",
|
|
|
|
Matches: []Match{
|
|
|
|
{"gemini://example.com/path", true},
|
|
|
|
{"gemini://example.com/", true},
|
|
|
|
{"gemini://example.com/path.gmi", true},
|
|
|
|
{"gemini://example.com/path/", true},
|
|
|
|
{"gemini://example.org/path", false},
|
|
|
|
{"http://example.com/path", false},
|
|
|
|
{"http://example.org/path", false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// scheme: gemini, hostname: example.com, path: /path
|
|
|
|
Pattern: "example.com/path",
|
|
|
|
Matches: []Match{
|
|
|
|
{"gemini://example.com/path", true},
|
|
|
|
{"gemini://example.com/", false},
|
|
|
|
{"gemini://example.com/path.gmi", false},
|
|
|
|
{"gemini://example.com/path/", false},
|
|
|
|
{"gemini://example.org/path", false},
|
|
|
|
{"http://example.com/path", false},
|
|
|
|
{"http://example.org/path", false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// scheme: gemini, hostname: example.com, path: /subtree/*
|
|
|
|
Pattern: "example.com/subtree/",
|
|
|
|
Matches: []Match{
|
|
|
|
{"gemini://example.com/subtree/", true},
|
|
|
|
{"gemini://example.com/subtree/nested/", true},
|
|
|
|
{"gemini://example.com/subtree/nested/file", true},
|
|
|
|
{"gemini://example.org/subtree/", false},
|
|
|
|
{"gemini://example.org/subtree/nested/", false},
|
|
|
|
{"gemini://example.org/subtree/nested/file", false},
|
|
|
|
{"gemini://example.com/subtree", false},
|
|
|
|
{"gemini://www.example.com/subtree/", false},
|
|
|
|
{"http://example.com/subtree/", false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// scheme: http, hostname: example.com, path: /*
|
|
|
|
Pattern: "http://example.com",
|
|
|
|
Matches: []Match{
|
|
|
|
{"http://example.com/path", true},
|
|
|
|
{"http://example.com/", true},
|
|
|
|
{"http://example.com/path.gmi", true},
|
|
|
|
{"http://example.com/path/", true},
|
|
|
|
{"http://example.org/path", false},
|
|
|
|
{"gemini://example.com/path", false},
|
|
|
|
{"gemini://example.org/path", false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// scheme: http, hostname: example.com, path: /path
|
|
|
|
Pattern: "http://example.com/path",
|
|
|
|
Matches: []Match{
|
|
|
|
{"http://example.com/path", true},
|
|
|
|
{"http://example.com/", false},
|
|
|
|
{"http://example.com/path.gmi", false},
|
|
|
|
{"http://example.com/path/", false},
|
|
|
|
{"http://example.org/path", false},
|
|
|
|
{"gemini://example.com/path", false},
|
|
|
|
{"gemini://example.org/path", false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// scheme: http, hostname: example.com, path: /subtree/*
|
|
|
|
Pattern: "http://example.com/subtree/",
|
|
|
|
Matches: []Match{
|
|
|
|
{"http://example.com/subtree/", true},
|
|
|
|
{"http://example.com/subtree/nested/", true},
|
|
|
|
{"http://example.com/subtree/nested/file", true},
|
|
|
|
{"http://example.org/subtree/", false},
|
|
|
|
{"http://example.org/subtree/nested/", false},
|
|
|
|
{"http://example.org/subtree/nested/file", false},
|
|
|
|
{"http://example.com/subtree", false},
|
|
|
|
{"http://www.example.com/subtree/", false},
|
|
|
|
{"gemini://example.com/subtree/", false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// scheme: *, hostname: example.com, path: /*
|
|
|
|
Pattern: "//example.com",
|
|
|
|
Matches: []Match{
|
|
|
|
{"gemini://example.com/path", true},
|
|
|
|
{"gemini://example.com/", true},
|
|
|
|
{"gemini://example.com/path.gmi", true},
|
|
|
|
{"gemini://example.com/path/", true},
|
|
|
|
{"gemini://example.org/path", false},
|
|
|
|
{"http://example.com/path", true},
|
|
|
|
{"http://example.org/path", false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// scheme: *, hostname: example.com, path: /path
|
|
|
|
Pattern: "//example.com/path",
|
|
|
|
Matches: []Match{
|
|
|
|
{"gemini://example.com/path", true},
|
|
|
|
{"gemini://example.com/", false},
|
|
|
|
{"gemini://example.com/path.gmi", false},
|
|
|
|
{"gemini://example.com/path/", false},
|
|
|
|
{"gemini://example.org/path", false},
|
|
|
|
{"http://example.com/path", true},
|
|
|
|
{"http://example.org/path", false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// scheme: *, hostname: example.com, path: /subtree/*
|
|
|
|
Pattern: "//example.com/subtree/",
|
|
|
|
Matches: []Match{
|
|
|
|
{"gemini://example.com/subtree/", true},
|
|
|
|
{"gemini://example.com/subtree/nested/", true},
|
|
|
|
{"gemini://example.com/subtree/nested/file", true},
|
|
|
|
{"gemini://example.org/subtree/", false},
|
|
|
|
{"gemini://example.org/subtree/nested/", false},
|
|
|
|
{"gemini://example.org/subtree/nested/file", false},
|
|
|
|
{"gemini://example.com/subtree", false},
|
|
|
|
{"gemini://www.example.com/subtree/", false},
|
|
|
|
{"http://example.com/subtree/", true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// scheme: http, hostname: *, path: /*
|
|
|
|
Pattern: "http://",
|
|
|
|
Matches: []Match{
|
|
|
|
{"http://example.com/path", true},
|
|
|
|
{"http://example.com/", true},
|
|
|
|
{"http://example.com/path.gmi", true},
|
|
|
|
{"http://example.com/path/", true},
|
|
|
|
{"http://example.org/path", true},
|
|
|
|
{"gemini://example.com/path", false},
|
|
|
|
{"gemini://example.org/path", false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// scheme: http, hostname: *, path: /path
|
|
|
|
Pattern: "http:///path",
|
|
|
|
Matches: []Match{
|
|
|
|
{"http://example.com/path", true},
|
|
|
|
{"http://example.com/", false},
|
|
|
|
{"http://example.com/path.gmi", false},
|
|
|
|
{"http://example.com/path/", false},
|
|
|
|
{"http://example.org/path", true},
|
|
|
|
{"gemini://example.com/path", false},
|
|
|
|
{"gemini://example.org/path", false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// scheme: http, hostname: *, path: /subtree/*
|
|
|
|
Pattern: "http:///subtree/",
|
|
|
|
Matches: []Match{
|
|
|
|
{"http://example.com/subtree/", true},
|
|
|
|
{"http://example.com/subtree/nested/", true},
|
|
|
|
{"http://example.com/subtree/nested/file", true},
|
|
|
|
{"http://example.org/subtree/", true},
|
|
|
|
{"http://example.org/subtree/nested/", true},
|
|
|
|
{"http://example.org/subtree/nested/file", true},
|
|
|
|
{"http://example.com/subtree", false},
|
|
|
|
{"http://www.example.com/subtree/", true},
|
|
|
|
{"gemini://example.com/subtree/", false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// scheme: *, hostname: *, path: /*
|
|
|
|
Pattern: "//",
|
|
|
|
Matches: []Match{
|
|
|
|
{"gemini://example.com/path", true},
|
|
|
|
{"gemini://example.com/", true},
|
|
|
|
{"gemini://example.com/path.gmi", true},
|
|
|
|
{"gemini://example.com/path/", true},
|
|
|
|
{"gemini://example.org/path", true},
|
|
|
|
{"http://example.com/path", true},
|
|
|
|
{"http://example.org/path", true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// scheme: *, hostname: *, path: /path
|
|
|
|
Pattern: "///path",
|
|
|
|
Matches: []Match{
|
|
|
|
{"gemini://example.com/path", true},
|
|
|
|
{"gemini://example.com/", false},
|
|
|
|
{"gemini://example.com/path.gmi", false},
|
|
|
|
{"gemini://example.com/path/", false},
|
|
|
|
{"gemini://example.org/path", true},
|
|
|
|
{"http://example.com/path", true},
|
|
|
|
{"http://example.org/path", true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// scheme: *, hostname: *, path: /subtree/*
|
|
|
|
Pattern: "///subtree/",
|
|
|
|
Matches: []Match{
|
|
|
|
{"gemini://example.com/subtree/", true},
|
|
|
|
{"gemini://example.com/subtree/nested/", true},
|
|
|
|
{"gemini://example.com/subtree/nested/file", true},
|
|
|
|
{"gemini://example.org/subtree/", true},
|
|
|
|
{"gemini://example.org/subtree/nested/", true},
|
|
|
|
{"gemini://example.org/subtree/nested/file", true},
|
|
|
|
{"gemini://example.com/subtree", false},
|
|
|
|
{"gemini://www.example.com/subtree/", true},
|
|
|
|
{"http://example.com/subtree/", true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// scheme: gemini, hostname: *.example.com, path: /*
|
|
|
|
Pattern: "*.example.com",
|
|
|
|
Matches: []Match{
|
|
|
|
{"gemini://mail.example.com/", true},
|
|
|
|
{"gemini://www.example.com/index.gmi", true},
|
|
|
|
{"gemini://example.com/", false},
|
|
|
|
{"gemini://a.b.example.com/", false},
|
|
|
|
{"http://www.example.com/", false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// scheme: http, hostname: *.example.com, path: /*
|
|
|
|
Pattern: "http://*.example.com",
|
|
|
|
Matches: []Match{
|
|
|
|
{"http://mail.example.com/", true},
|
|
|
|
{"http://www.example.com/index.gmi", true},
|
|
|
|
{"http://example.com/", false},
|
|
|
|
{"http://a.b.example.com/", false},
|
|
|
|
{"gemini://www.example.com/", false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, test := range tests {
|
|
|
|
h := &nopHandler{}
|
|
|
|
var mux ServeMux
|
|
|
|
mux.Handle(test.Pattern, h)
|
|
|
|
|
|
|
|
for _, match := range tests[i].Matches {
|
|
|
|
u, err := url.Parse(match.URL)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
got := mux.Handler(&Request{URL: u})
|
|
|
|
if match.Ok {
|
|
|
|
if h != got {
|
|
|
|
t.Errorf("expected %s to match %s", test.Pattern, match.URL)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if h == got {
|
|
|
|
t.Errorf("expected %s not to match %s", test.Pattern, match.URL)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|