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.
|
||||
|
||||
So far there are at least 3 packages:
|
||||
So far there are at least 4 packages:
|
||||
* log contains a simple request-logging middleware
|
||||
* fs has handlers that make file servers possible: serve files, build directory listings, etc
|
||||
* cgi includes handlers which can execute CGI programs
|
||||
* sharedhost which provides means of handling /~username URLs
|
||||
* ...with more to come
|
||||
|
||||
## 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.
|
||||
|
||||
So far there are at least 3 packages:
|
||||
So far there are at least 4 packages:
|
||||
|
||||
* log contains a simple request-logging middleware
|
||||
* fs has handlers that make file servers possible: serve files, build directory listings, etc
|
||||
* cgi includes handlers which can execute CGI programs
|
||||
* sharedhost which provides means of handling /~username URLs
|
||||
* ...with more to come
|
||||
|
||||
## 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