New sharedhost contrib package.
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
ReplaceTilde simply replaces a leading ~ in the URL. Fixes #9.
This commit is contained in:
parent
7d8fd81278
commit
e1aa19f1e8
|
@ -34,10 +34,11 @@ The gemtext package provides a parser and converters for gemtext documents. It e
|
||||||
|
|
||||||
This is where useful building blocks themselves start to come in. Sub-packages of contrib include Handler and Middleware implementations which accomplish the things your servers actually need to do.
|
This is where useful building blocks themselves start to come in. Sub-packages of contrib include Handler and Middleware implementations which accomplish the things your servers actually need to do.
|
||||||
|
|
||||||
So far there are at least 3 packages:
|
So far there are at least 4 packages:
|
||||||
* log contains a simple request-logging middleware
|
* log contains a simple request-logging middleware
|
||||||
* fs has handlers that make file servers possible: serve files, build directory listings, etc
|
* fs has handlers that make file servers possible: serve files, build directory listings, etc
|
||||||
* cgi includes handlers which can execute CGI programs
|
* cgi includes handlers which can execute CGI programs
|
||||||
|
* sharedhost which provides means of handling /~username URLs
|
||||||
* ...with more to come
|
* ...with more to come
|
||||||
|
|
||||||
## Get it
|
## Get it
|
||||||
|
|
|
@ -36,11 +36,12 @@ The gemtext package provides a parser and converters for gemtext documents. It e
|
||||||
|
|
||||||
This is where useful building blocks themselves start to come in. Sub-packages of contrib include Handler and Middleware implementations which accomplish the things your servers actually need to do.
|
This is where useful building blocks themselves start to come in. Sub-packages of contrib include Handler and Middleware implementations which accomplish the things your servers actually need to do.
|
||||||
|
|
||||||
So far there are at least 3 packages:
|
So far there are at least 4 packages:
|
||||||
|
|
||||||
* log contains a simple request-logging middleware
|
* log contains a simple request-logging middleware
|
||||||
* fs has handlers that make file servers possible: serve files, build directory listings, etc
|
* fs has handlers that make file servers possible: serve files, build directory listings, etc
|
||||||
* cgi includes handlers which can execute CGI programs
|
* cgi includes handlers which can execute CGI programs
|
||||||
|
* sharedhost which provides means of handling /~username URLs
|
||||||
* ...with more to come
|
* ...with more to come
|
||||||
|
|
||||||
## Get it
|
## Get it
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
package sharedhost
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"tildegit.org/tjp/gus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReplaceTilde builds a middleware which substitutes a leading '~' in the request path.
|
||||||
|
//
|
||||||
|
// It makes the alteration to a copy of the request which is then passed into the
|
||||||
|
// wrapped Handler. This way middlewares outside of this one inspecting the request
|
||||||
|
// afterwards will see the original URL.
|
||||||
|
//
|
||||||
|
// Typically the replacement should end with a "/", so that the ~ ends up mapping to a
|
||||||
|
// particular directory on the filesystem. For instance with a replacement string of
|
||||||
|
// "users/", "domain.com/~jim/index.gmi" maps to "domain.com/users/jim/index.gmi".
|
||||||
|
func ReplaceTilde(replacement string) gus.Middleware {
|
||||||
|
return func(inner gus.Handler) gus.Handler {
|
||||||
|
return func(ctx context.Context, request *gus.Request) *gus.Response {
|
||||||
|
if len(request.Path) > 1 && request.Path[0] == '/' && request.Path[1] == '~' {
|
||||||
|
request = cloneRequest(request)
|
||||||
|
request.Path = "/" + replacement + request.Path[2:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return inner(ctx, request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func cloneRequest(start *gus.Request) *gus.Request {
|
||||||
|
next := &gus.Request{}
|
||||||
|
*next = *start
|
||||||
|
|
||||||
|
next.URL = &url.URL{}
|
||||||
|
*next.URL = *start.URL
|
||||||
|
|
||||||
|
if start.TLSState != nil {
|
||||||
|
next.TLSState = &tls.ConnectionState{}
|
||||||
|
*next.TLSState = *start.TLSState
|
||||||
|
}
|
||||||
|
|
||||||
|
return next
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package sharedhost_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"tildegit.org/tjp/gus"
|
||||||
|
"tildegit.org/tjp/gus/contrib/sharedhost"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReplaceTilde(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
replacement string
|
||||||
|
inputURL string
|
||||||
|
replacedPath string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
replacement: "users/",
|
||||||
|
inputURL: "gemini://domain.com/~username/foo/bar",
|
||||||
|
replacedPath: "/users/username/foo/bar",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
replacement: "people-",
|
||||||
|
inputURL: "gemini://domain.com/non/match",
|
||||||
|
replacedPath: "/non/match",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
replacement: "people-",
|
||||||
|
inputURL: "gemini://domain.com/~someone/dir/file",
|
||||||
|
replacedPath: "/people-someone/dir/file",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.inputURL, func(t *testing.T) {
|
||||||
|
u, err := url.Parse(test.inputURL)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
originalPath := u.Path
|
||||||
|
|
||||||
|
replacer := sharedhost.ReplaceTilde(test.replacement)
|
||||||
|
request := &gus.Request{URL: u}
|
||||||
|
handler := replacer(func(_ context.Context, request *gus.Request) *gus.Response {
|
||||||
|
assert.Equal(t, test.replacedPath, request.Path)
|
||||||
|
return &gus.Response{}
|
||||||
|
})
|
||||||
|
|
||||||
|
handler(context.Background(), request)
|
||||||
|
|
||||||
|
// original request was unmodified
|
||||||
|
assert.Equal(t, originalPath, request.Path)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue