summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortjpcc <tjp@ctrl-c.club>2023-05-01 07:56:25 -0600
committertjpcc <tjp@ctrl-c.club>2023-05-01 07:56:25 -0600
commit9a2da81b11ad0064cca24ce7974827d032309369 (patch)
tree4313224dc089208423e78bffc3ec50833e35bcea
parent21e2758145d100d74013060f7090d84679cae683 (diff)
name change gus -> sliderule
-rw-r--r--README.gmi36
-rw-r--r--README.md34
-rw-r--r--contrib/cgi/cgi.go6
-rw-r--r--contrib/cgi/cgi_test.go10
-rw-r--r--contrib/cgi/gemini.go8
-rw-r--r--contrib/cgi/gopher.go8
-rw-r--r--contrib/cgi/spartan.go8
-rw-r--r--contrib/fs/dir.go8
-rw-r--r--contrib/fs/dir_test.go14
-rw-r--r--contrib/fs/file.go4
-rw-r--r--contrib/fs/file_test.go10
-rw-r--r--contrib/fs/gemini.go18
-rw-r--r--contrib/fs/gopher.go18
-rw-r--r--contrib/fs/spartan.go18
-rw-r--r--contrib/sharedhost/replacement.go12
-rw-r--r--contrib/sharedhost/replacement_test.go10
-rw-r--r--contrib/tlsauth/approver_test.go2
-rw-r--r--contrib/tlsauth/auth.go12
-rw-r--r--contrib/tlsauth/auth_test.go38
-rw-r--r--contrib/tlsauth/gemini.go20
-rw-r--r--contrib/tlsauth/gemini_test.go22
-rw-r--r--examples/cgi/main.go6
-rw-r--r--examples/cowsay/main.go8
-rw-r--r--examples/fetch/main.go6
-rw-r--r--examples/fileserver/main.go10
-rw-r--r--examples/finger/main.go4
-rw-r--r--examples/gmi2html/main.go4
-rw-r--r--examples/gmi2md/main.go4
-rw-r--r--examples/gopher_fileserver/main.go12
-rw-r--r--examples/inspectls/main.go8
-rw-r--r--finger/request.go12
-rw-r--r--finger/request_test.go2
-rw-r--r--finger/response.go10
-rw-r--r--finger/serve.go12
-rw-r--r--finger/system.go6
-rw-r--r--gemini/client.go4
-rw-r--r--gemini/gemtext/fuzz_test.go2
-rw-r--r--gemini/gemtext/htmlconv/convert.go4
-rw-r--r--gemini/gemtext/htmlconv/convert_test.go4
-rw-r--r--gemini/gemtext/internal/templates.go2
-rw-r--r--gemini/gemtext/mdconv/convert.go4
-rw-r--r--gemini/gemtext/mdconv/convert_test.go4
-rw-r--r--gemini/gemtext/parse_line_test.go2
-rw-r--r--gemini/gemtext/parse_test.go2
-rw-r--r--gemini/request.go20
-rw-r--r--gemini/request_test.go2
-rw-r--r--gemini/response.go100
-rw-r--r--gemini/response_test.go20
-rw-r--r--gemini/roundtrip_test.go12
-rw-r--r--gemini/serve.go32
-rw-r--r--go.mod2
-rw-r--r--gopher/client.go6
-rw-r--r--gopher/gophermap/parse.go6
-rw-r--r--gopher/gophermap/parse_test.go4
-rw-r--r--gopher/request.go8
-rw-r--r--gopher/request_test.go2
-rw-r--r--gopher/response.go70
-rw-r--r--gopher/serve.go14
-rw-r--r--handler.go2
-rw-r--r--handler_test.go28
-rw-r--r--internal/pathtree_test.go2
-rw-r--r--logging/middleware.go14
-rw-r--r--logging/middleware_test.go10
-rw-r--r--request.go8
-rw-r--r--request_test.go6
-rw-r--r--response.go2
-rw-r--r--router.go4
-rw-r--r--router_test.go22
-rw-r--r--server.go2
-rw-r--r--spartan/client.go4
-rw-r--r--spartan/request.go26
-rw-r--r--spartan/request_test.go2
-rw-r--r--spartan/response.go36
-rw-r--r--spartan/serve.go36
74 files changed, 483 insertions, 467 deletions
diff --git a/README.gmi b/README.gmi
index 980d380..7c590b6 100644
--- a/README.gmi
+++ b/README.gmi
@@ -1,12 +1,12 @@
-# Gus: The small web toolkit for Go
+# sliderule: The small web toolkit for Go
-Gus is the toolkit for working with the small web in Go.
+Sliderule is the toolkit for working with the small web in Go.
Think of it as a net/http for small web protocols. You still have to write your server, but you can focus on the logic you want to implement knowing the protocol is already dealt with. It's been said of gemini that you can write your server in a day. Now you can write it in well under an hour.
-## The "gus" package
+## The "sliderule" package
-Gus is carefully structured as composable building blocks. The top-level package defines the framework in which servers and clients can be built.
+Sliderule is carefully structured as composable building blocks. The top-level package defines the framework in which servers and clients can be built.
* a request type
* a response type
@@ -17,7 +17,7 @@ Gus is carefully structured as composable building blocks. The top-level package
## Protocols
-The packages gus/gemini, gus/gopher, and gus/finger provide concrete implementations of gus abstractions specific to those protocols.
+The packages sliderule/gemini, sliderule/gopher, and sliderule/finger provide concrete implementations specific to those protocols.
* I/O (parsing, formatting) request and responses
* constructors for the various kinds of protocol responses
* helpers for building a protocol-suitable TLS config
@@ -25,23 +25,23 @@ The packages gus/gemini, gus/gopher, and gus/finger provide concrete implementat
* Servers which can run your Handlers.
The primary text formats for those protocols have higher-level support provided in sub-packages:
-* gus/gemini/gemtext supports parsing gemtext and getting direct programmatic access to its AST. Deeper sub-packages provide converters to other formats (markdown and HTML) with overridable templates.
-* gus/gopher/gophermap similarly parses the gophermap format and provides access to its AST.
+* sliderule/gemini/gemtext supports parsing gemtext and getting direct programmatic access to its AST. Deeper sub-packages provide converters to other formats (markdown and HTML) with overridable templates.
+* sliderule/gopher/gophermap similarly parses the gophermap format and provides access to its AST.
## Logging
-Gus borrows the logging interface from go-kit.
+Sliderule borrows the logging interface from go-kit.
=> https://pkg.go.dev/github.com/go-kit/log#Logger The logger interface from go-kit/log.
-The gus/logging package provides everything you need to get a good basic start to producing helpful logs.
+The sliderule/logging package provides everything you need to get a good basic start to producing helpful logs.
* A request-logging middleware with common diagnostics (time, duration, url, status codes, response body lengths)
* A simple constructor of useful default loggers at various levels. They output colorful logfmt lines to stdout.
## Routing
-The router in the gus package supports slash-delimited path pattern strings. In the segments of these patterns:
+The router in the sliderule package supports slash-delimited path pattern strings. In the segments of these patterns:
* A "/:wildcard/" segment matches anything in that position, and captures the value as a route parameter. Or if the paramter name is omitted like "/:/", it matches anything in a single segment without capturing a paramter.
* A "/*remainder" segment is only allowed at the end and matches the rest of the path, capturing it into the paramter name. Or again, omitting a parameter name like "/*" simple matches any path suffix.
@@ -49,7 +49,7 @@ The router in the gus package supports slash-delimited path pattern strings. In
Router also supports maintaining a list of middlewares at the router level, mounting sub-routers under a pattern, looking up the matching handler for any request, and of course acting as a Handler itself.
-## gus/contrib/*
+## sliderule/contrib/*
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.
@@ -62,29 +62,29 @@ The sub-packages include:
## Get it
-### Using gus in your project
+### Using sliderule in your project
To add it to your own go project:
-```shell command to add a dependency on gus in a go module
-$ go get tildegit.org/tjp/gus
+```shell command to add a dependency on sliderule in a go module
+$ go get tildegit.org/tjp/sliderule
```
### Straight to the code please
-=> https://tildegit.org/tjp/gus The code is hosted here on tildegit.
-=> https://pkg.go.dev/tildegit.org/tjp/gus The generated documentation is on the go package index.
+=> https://tildegit.org/tjp/sliderule The code is hosted here on tildegit.
+=> https://pkg.go.dev/tildegit.org/tjp/sliderule The generated documentation is on the go package index.
### Verify releases
Since v0.9.0, releases are signed with minisign. The signature file is included in the release downloads page, and the public key is RWSzQywJwHgjSMD0y0RXwXAGpapcMJplwbCVYQqabhAJ+NAnKAeh98Vb - this is also referenced on tjp's home page on gemini.
-=> gemini://gemini.ctrl-c.club/~tjp TJP's home page, which also mentions the public key used for signing gus releases.
+=> gemini://gemini.ctrl-c.club/~tjp TJP's home page, which also mentions the public key used for signing sliderule releases.
## Contribute
There's lots still to do, and contributions are very welcome!
-=> https://tildegit.org/tjp/gus submit an issue or pull request on the tildegit repository,
+=> https://tildegit.org/tjp/sliderule submit an issue or pull request on the tildegit repository,
=> mailto:tjp@ctrl-c.club send me an email directly,
or poke me on IRC: I'm @tjp on irc.tilde.chat where you'll find me in #gemini
diff --git a/README.md b/README.md
index 592f652..9395dcd 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,13 @@
-# Gus: The small web toolkit for Go
+# sliderule: The small web toolkit for Go
-Gus is the toolkit for working with the small web in Go.
+Sliderule is the toolkit for working with the small web in Go.
Think of it as a net/http for small web protocols. You still have to write your server, but you can focus on the logic you want to implement knowing the protocol is already dealt with. It's been said of gemini that you can write your server in a day. Now you can write it in well under an hour.
-## The "gus" package
+## The "sliderule" package
-Gus is carefully structured as composable building blocks. The top-level package defines the framework in which servers and clients can be built.
+Sliderule is carefully structured as composable building blocks. The top-level package defines the framework in which servers and clients can be built.
* a request type
* a response type
@@ -18,7 +18,7 @@ Gus is carefully structured as composable building blocks. The top-level package
## Protocols
-The packages gus/gemini, gus/gopher, and gus/finger provide concrete implementations of gus abstractions specific to those protocols.
+The packages sliderule/gemini, sliderule/gopher, and sliderule/finger provide concrete implementations specific to those protocols.
* I/O (parsing, formatting) request and responses
* constructors for the various kinds of protocol responses
@@ -28,23 +28,23 @@ The packages gus/gemini, gus/gopher, and gus/finger provide concrete implementat
The primary text formats for those protocols have higher-level support provided in sub-packages:
-* gus/gemini/gemtext supports parsing gemtext and getting direct programmatic access to its AST. Deeper sub-packages provide converters to other formats (markdown and HTML) with overridable templates.
-* gus/gopher/gophermap similarly parses the gophermap format and provides access to its AST.
+* sliderule/gemini/gemtext supports parsing gemtext and getting direct programmatic access to its AST. Deeper sub-packages provide converters to other formats (markdown and HTML) with overridable templates.
+* sliderule/gopher/gophermap similarly parses the gophermap format and provides access to its AST.
## Logging
-Gus borrows the logging interface from go-kit.
+Sliderule borrows the logging interface from go-kit.
=> [The logger interface from go-kit/log.](https://pkg.go.dev/github.com/go-kit/log#Logger)
-The gus/logging package provides everything you need to get a good basic start to producing helpful logs.
+The sliderule/logging package provides everything you need to get a good basic start to producing helpful logs.
* A request-logging middleware with common diagnostics (time, duration, url, status codes, response body lengths)
* A simple constructor of useful default loggers at various levels. They output colorful logfmt lines to stdout.
## Routing
-The router in the gus package supports slash-delimited path pattern strings. In the segments of these patterns:
+The router in the sliderule package supports slash-delimited path pattern strings. In the segments of these patterns:
* A "/:wildcard/" segment matches anything in that position, and captures the value as a route parameter. Or if the paramter name is omitted like "/:/", it matches anything in a single segment without capturing a paramter.
* A "/*remainder" segment is only allowed at the end and matches the rest of the path, capturing it into the paramter name. Or again, omitting a parameter name like "/*" simple matches any path suffix.
@@ -52,7 +52,7 @@ The router in the gus package supports slash-delimited path pattern strings. In
Router also supports maintaining a list of middlewares at the router level, mounting sub-routers under a pattern, looking up the matching handler for any request, and of course acting as a Handler itself.
-## gus/contrib/*
+## sliderule/contrib/*
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.
@@ -66,31 +66,31 @@ The sub-packages include:
## Get it
-### Using gus in your project
+### Using sliderule in your project
To add it to your own go project:
```
-$ go get tildegit.org/tjp/gus
+$ go get tildegit.org/tjp/sliderule
```
### Straight to the code please
-=> [The code is hosted here on tildegit.](https://tildegit.org/tjp/gus)
+=> [The code is hosted here on tildegit.](https://tildegit.org/tjp/sliderule)
-=> [The generated documentation is on the go package index.](https://pkg.go.dev/tildegit.org/tjp/gus)
+=> [The generated documentation is on the go package index.](https://pkg.go.dev/tildegit.org/tjp/sliderule)
### Verify releases
Since v0.9.0, releases are signed with minisign. The signature file is included in the release downloads page, and the public key is RWSzQywJwHgjSMD0y0RXwXAGpapcMJplwbCVYQqabhAJ+NAnKAeh98Vb - this is also referenced on tjp's home page on gemini.
-=> [TJP's home page, which also mentions the public key used for signing gus releases.](gemini://gemini.ctrl-c.club/~tjp)
+=> [TJP's home page, which also mentions the public key used for signing sliderule releases.](gemini://gemini.ctrl-c.club/~tjp)
## Contribute
There's lots still to do, and contributions are very welcome!
-=> [submit an issue or pull request on the tildegit repository,](https://tildegit.org/tjp/gus)
+=> [submit an issue or pull request on the tildegit repository,](https://tildegit.org/tjp/sliderule)
=> [send me an email directly,](mailto:tjp@ctrl-c.club)
diff --git a/contrib/cgi/cgi.go b/contrib/cgi/cgi.go
index e57f2d0..6c727aa 100644
--- a/contrib/cgi/cgi.go
+++ b/contrib/cgi/cgi.go
@@ -13,7 +13,7 @@ import (
"os/exec"
"strings"
- "tildegit.org/tjp/gus"
+ sr "tildegit.org/tjp/sliderule"
)
// ResolveCGI finds a CGI program corresponding to a request path.
@@ -91,7 +91,7 @@ func isNotExistError(err error) bool {
// RunCGI runs a specific program as a CGI script.
func RunCGI(
ctx context.Context,
- request *gus.Request,
+ request *sr.Request,
executable string,
pathInfo string,
) (io.Reader, int, error) {
@@ -130,7 +130,7 @@ func RunCGI(
func prepareCGIEnv(
ctx context.Context,
- request *gus.Request,
+ request *sr.Request,
scriptName string,
pathInfo string,
) []string {
diff --git a/contrib/cgi/cgi_test.go b/contrib/cgi/cgi_test.go
index 5c1ca33..ff2c45d 100644
--- a/contrib/cgi/cgi_test.go
+++ b/contrib/cgi/cgi_test.go
@@ -12,9 +12,9 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/contrib/cgi"
- "tildegit.org/tjp/gus/gemini"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/contrib/cgi"
+ "tildegit.org/tjp/sliderule/gemini"
)
func TestCGIDirectory(t *testing.T) {
@@ -30,7 +30,7 @@ func TestCGIDirectory(t *testing.T) {
tests := []struct {
requestPath string
- responseCode gus.Status
+ responseCode sr.Status
responseBody string
}{
{
@@ -69,7 +69,7 @@ func TestCGIDirectory(t *testing.T) {
code, err := strconv.Atoi(string(response[:2]))
if assert.Nil(t, err) {
- assert.Equal(t, test.responseCode, gus.Status(code))
+ assert.Equal(t, test.responseCode, sr.Status(code))
}
_, body, found := strings.Cut(string(response), "\r\n")
diff --git a/contrib/cgi/gemini.go b/contrib/cgi/gemini.go
index 1587037..d245c8e 100644
--- a/contrib/cgi/gemini.go
+++ b/contrib/cgi/gemini.go
@@ -5,8 +5,8 @@ import (
"fmt"
"strings"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/gemini"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/gemini"
)
// GeminiCGIDirectory runs any executable files relative to a root directory on the file system.
@@ -15,9 +15,9 @@ import (
// a request for /foo/bar/baz can also run an executable found at /foo or /foo/bar. In
// such a case the PATH_INFO environment variable will include the remaining portion of
// the URI path.
-func GeminiCGIDirectory(pathRoot, fsRoot string) gus.Handler {
+func GeminiCGIDirectory(pathRoot, fsRoot string) sr.Handler {
fsRoot = strings.TrimRight(fsRoot, "/")
- return gus.HandlerFunc(func(ctx context.Context, request *gus.Request) *gus.Response {
+ return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response {
if !strings.HasPrefix(request.Path, pathRoot) {
return nil
}
diff --git a/contrib/cgi/gopher.go b/contrib/cgi/gopher.go
index 4378eb7..290adfa 100644
--- a/contrib/cgi/gopher.go
+++ b/contrib/cgi/gopher.go
@@ -5,8 +5,8 @@ import (
"fmt"
"strings"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/gopher"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/gopher"
)
// GopherCGIDirectory runs any executable files relative to a root directory on the file system.
@@ -15,9 +15,9 @@ import (
// a request for /foo/bar/baz can also run an executable found at /foo or /foo/bar. In
// such a case the PATH_INFO environment variable will include the remaining portion of
// the URI path.
-func GopherCGIDirectory(pathRoot, fsRoot string) gus.Handler {
+func GopherCGIDirectory(pathRoot, fsRoot string) sr.Handler {
fsRoot = strings.TrimRight(fsRoot, "/")
- return gus.HandlerFunc(func(ctx context.Context, request *gus.Request) *gus.Response {
+ return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response {
if !strings.HasPrefix(request.Path, pathRoot) {
return nil
}
diff --git a/contrib/cgi/spartan.go b/contrib/cgi/spartan.go
index 01ebb19..6994466 100644
--- a/contrib/cgi/spartan.go
+++ b/contrib/cgi/spartan.go
@@ -5,8 +5,8 @@ import (
"fmt"
"strings"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/spartan"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/spartan"
)
// SpartanCGIDirectory runs executable files relative to a root directory in the file system.
@@ -14,9 +14,9 @@ import (
// It will also find any run any executable _part way_ through the path, so for example a
// request for /foo/bar/baz can also run an executable found at /foo or /foo/bar. In such
// a case the PATH_INFO environment variable will include the remaining portion of the URI.
-func SpartanCGIDirectory(pathRoot, fsRoot string) gus.Handler {
+func SpartanCGIDirectory(pathRoot, fsRoot string) sr.Handler {
fsRoot = strings.TrimRight(fsRoot, "/")
- return gus.HandlerFunc(func(ctx context.Context, request *gus.Request) *gus.Response {
+ return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response {
if !strings.HasPrefix(request.Path, pathRoot) {
return nil
}
diff --git a/contrib/fs/dir.go b/contrib/fs/dir.go
index 5659804..bb2d933 100644
--- a/contrib/fs/dir.go
+++ b/contrib/fs/dir.go
@@ -8,7 +8,7 @@ import (
"strings"
"text/template"
- "tildegit.org/tjp/gus"
+ sr "tildegit.org/tjp/sliderule"
)
// ResolveDirectory opens the directory corresponding to a request path.
@@ -16,7 +16,7 @@ import (
// The string is the full path to the directory. If the returned ReadDirFile
// is not nil, it will be open and must be closed by the caller.
func ResolveDirectory(
- request *gus.Request,
+ request *sr.Request,
fileSystem fs.FS,
) (string, fs.ReadDirFile, error) {
path := strings.Trim(request.Path, "/")
@@ -102,7 +102,7 @@ func RenderDirectoryListing(
path string,
dir fs.ReadDirFile,
template *template.Template,
- server gus.Server,
+ server sr.Server,
) (io.Reader, error) {
buf := &bytes.Buffer{}
@@ -118,7 +118,7 @@ func RenderDirectoryListing(
return buf, nil
}
-func dirlistNamespace(path string, dirFile fs.ReadDirFile, server gus.Server) (map[string]any, error) {
+func dirlistNamespace(path string, dirFile fs.ReadDirFile, server sr.Server) (map[string]any, error) {
entries, err := dirFile.ReadDir(0)
if err != nil {
return nil, err
diff --git a/contrib/fs/dir_test.go b/contrib/fs/dir_test.go
index 9c6770d..6b6f60f 100644
--- a/contrib/fs/dir_test.go
+++ b/contrib/fs/dir_test.go
@@ -10,9 +10,9 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/contrib/fs"
- "tildegit.org/tjp/gus/gemini"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/contrib/fs"
+ "tildegit.org/tjp/sliderule/gemini"
)
func TestDirectoryDefault(t *testing.T) {
@@ -20,7 +20,7 @@ func TestDirectoryDefault(t *testing.T) {
tests := []struct {
url string
- status gus.Status
+ status sr.Status
meta string
body string
}{
@@ -46,7 +46,7 @@ func TestDirectoryDefault(t *testing.T) {
u, err := url.Parse(test.url)
require.Nil(t, err)
- request := &gus.Request{URL: u}
+ request := &sr.Request{URL: u}
response := handler.Handle(context.Background(), request)
if response == nil {
@@ -73,7 +73,7 @@ func TestDirectoryListing(t *testing.T) {
tests := []struct {
url string
- status gus.Status
+ status sr.Status
meta string
body string
}{
@@ -107,7 +107,7 @@ func TestDirectoryListing(t *testing.T) {
u, err := url.Parse(test.url)
require.Nil(t, err)
- request := &gus.Request{URL: u}
+ request := &sr.Request{URL: u}
response := handler.Handle(context.Background(), request)
if response == nil {
diff --git a/contrib/fs/file.go b/contrib/fs/file.go
index a1293af..591c1bd 100644
--- a/contrib/fs/file.go
+++ b/contrib/fs/file.go
@@ -5,7 +5,7 @@ import (
"mime"
"strings"
- "tildegit.org/tjp/gus"
+ sr "tildegit.org/tjp/sliderule"
)
// ResolveFile finds a file from a filesystem based on a request path.
@@ -13,7 +13,7 @@ import (
// It only returns a non-nil file if a file is found - not a directory.
// If there is any other sort of filesystem access error, it will be
// returned.
-func ResolveFile(request *gus.Request, fileSystem fs.FS) (string, fs.File, error) {
+func ResolveFile(request *sr.Request, fileSystem fs.FS) (string, fs.File, error) {
filepath := strings.TrimPrefix(request.Path, "/")
file, err := fileSystem.Open(filepath)
if isNotFound(err) {
diff --git a/contrib/fs/file_test.go b/contrib/fs/file_test.go
index 3949b83..55e2a09 100644
--- a/contrib/fs/file_test.go
+++ b/contrib/fs/file_test.go
@@ -10,9 +10,9 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/contrib/fs"
- "tildegit.org/tjp/gus/gemini"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/contrib/fs"
+ "tildegit.org/tjp/sliderule/gemini"
)
func TestFileHandler(t *testing.T) {
@@ -20,7 +20,7 @@ func TestFileHandler(t *testing.T) {
tests := []struct {
url string
- status gus.Status
+ status sr.Status
meta string
body string
}{
@@ -57,7 +57,7 @@ func TestFileHandler(t *testing.T) {
u, err := url.Parse(test.url)
require.Nil(t, err)
- request := &gus.Request{URL: u}
+ request := &sr.Request{URL: u}
response := handler.Handle(context.Background(), request)
if response == nil {
diff --git a/contrib/fs/gemini.go b/contrib/fs/gemini.go
index 21ca32d..fbf8d08 100644
--- a/contrib/fs/gemini.go
+++ b/contrib/fs/gemini.go
@@ -6,15 +6,15 @@ import (
"strings"
"text/template"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/gemini"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/gemini"
)
// GeminiFileHandler builds a handler which serves up files from a file system.
//
// It only serves responses for paths which do not correspond to directories on disk.
-func GeminiFileHandler(fileSystem fs.FS) gus.Handler {
- return gus.HandlerFunc(func(ctx context.Context, request *gus.Request) *gus.Response {
+func GeminiFileHandler(fileSystem fs.FS) sr.Handler {
+ return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response {
filepath, file, err := ResolveFile(request, fileSystem)
if err != nil {
return gemini.Failure(err)
@@ -41,8 +41,8 @@ func GeminiFileHandler(fileSystem fs.FS) gus.Handler {
//
// It requires that files from the provided fs.FS implement fs.ReadDirFile. If they
// don't, it will produce nil responses for any directory paths.
-func GeminiDirectoryDefault(fileSystem fs.FS, filenames ...string) gus.Handler {
- return gus.HandlerFunc(func(ctx context.Context, request *gus.Request) *gus.Response {
+func GeminiDirectoryDefault(fileSystem fs.FS, filenames ...string) sr.Handler {
+ return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response {
dirpath, dir, response := handleDirGemini(request, fileSystem)
if response != nil {
return response
@@ -77,8 +77,8 @@ func GeminiDirectoryDefault(fileSystem fs.FS, filenames ...string) gus.Handler {
//
// The template may be nil, in which case DefaultGeminiDirectoryList is used instead. The
// template is then processed with RenderDirectoryListing.
-func GeminiDirectoryListing(fileSystem fs.FS, template *template.Template) gus.Handler {
- return gus.HandlerFunc(func(ctx context.Context, request *gus.Request) *gus.Response {
+func GeminiDirectoryListing(fileSystem fs.FS, template *template.Template) sr.Handler {
+ return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response {
dirpath, dir, response := handleDirGemini(request, fileSystem)
if response != nil {
return response
@@ -109,7 +109,7 @@ var DefaultGeminiDirectoryList = template.Must(template.New("gemini_dirlist").Pa
=> ../
`[1:]))
-func handleDirGemini(request *gus.Request, fileSystem fs.FS) (string, fs.ReadDirFile, *gus.Response) {
+func handleDirGemini(request *sr.Request, fileSystem fs.FS) (string, fs.ReadDirFile, *sr.Response) {
path, dir, err := ResolveDirectory(request, fileSystem)
if err != nil {
return "", nil, gemini.Failure(err)
diff --git a/contrib/fs/gopher.go b/contrib/fs/gopher.go
index f63785c..e7e4ab9 100644
--- a/contrib/fs/gopher.go
+++ b/contrib/fs/gopher.go
@@ -8,15 +8,15 @@ import (
"strings"
"text/template"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/gopher"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/gopher"
)
// GopherFileHandler builds a handler which serves up files from a file system.
//
// It only serves responses for paths which correspond to files, not directories.
-func GopherFileHandler(fileSystem fs.FS) gus.Handler {
- return gus.HandlerFunc(func(ctx context.Context, request *gus.Request) *gus.Response {
+func GopherFileHandler(fileSystem fs.FS) sr.Handler {
+ return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response {
filepath, file, err := ResolveFile(request, fileSystem)
if err != nil {
return gopher.Error(err).Response()
@@ -39,8 +39,8 @@ func GopherFileHandler(fileSystem fs.FS) gus.Handler {
//
// It requires that files from the provided fs.FS implement fs.ReadDirFile. If
// they don't, it will produce nil responses for all directory paths.
-func GopherDirectoryDefault(fileSystem fs.FS, filenames ...string) gus.Handler {
- return gus.HandlerFunc(func(ctx context.Context, request *gus.Request) *gus.Response {
+func GopherDirectoryDefault(fileSystem fs.FS, filenames ...string) sr.Handler {
+ return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response {
dirpath, dir, err := ResolveDirectory(request, fileSystem)
if err != nil {
return gopher.Error(err).Response()
@@ -71,8 +71,8 @@ func GopherDirectoryDefault(fileSystem fs.FS, filenames ...string) gus.Handler {
//
// A template may be nil, in which case DefaultGopherDirectoryList is used instead. The
// template is then processed with RenderDirectoryListing.
-func GopherDirectoryListing(fileSystem fs.FS, tpl *template.Template) gus.Handler {
- return gus.HandlerFunc(func(ctx context.Context, request *gus.Request) *gus.Response {
+func GopherDirectoryListing(fileSystem fs.FS, tpl *template.Template) sr.Handler {
+ return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response {
dirpath, dir, err := ResolveDirectory(request, fileSystem)
if err != nil {
return gopher.Error(err).Response()
@@ -130,7 +130,7 @@ i {{ $hostname }} {{ $port }}
)
// GuessGopherItemType attempts to find the best gopher item type for a file based on its name.
-func GuessGopherItemType(filepath string) gus.Status {
+func GuessGopherItemType(filepath string) sr.Status {
ext := path.Ext(filepath)
switch ext {
case "txt", "gmi":
diff --git a/contrib/fs/spartan.go b/contrib/fs/spartan.go
index 550f549..70943ee 100644
--- a/contrib/fs/spartan.go
+++ b/contrib/fs/spartan.go
@@ -6,15 +6,15 @@ import (
"strings"
"text/template"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/spartan"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/spartan"
)
// SpartanFileHandler builds a handler which serves up files from a filesystem.
//
// It only serves responses for paths which do not correspond to directories on disk.
-func SpartanFileHandler(fileSystem fs.FS) gus.Handler {
- return gus.HandlerFunc(func(ctx context.Context, request *gus.Request) *gus.Response {
+func SpartanFileHandler(fileSystem fs.FS) sr.Handler {
+ return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response {
filepath, file, err := ResolveFile(request, fileSystem)
if err != nil {
return spartan.ClientError(err)
@@ -41,8 +41,8 @@ func SpartanFileHandler(fileSystem fs.FS) gus.Handler {
//
// It requires that files from the provided fs.FS implement fs.ReadDirFile. If they
// don't, it will produce nil responses for any directory paths.
-func SpartanDirectoryDefault(fileSystem fs.FS, filenames ...string) gus.Handler {
- return gus.HandlerFunc(func(ctx context.Context, request *gus.Request) *gus.Response {
+func SpartanDirectoryDefault(fileSystem fs.FS, filenames ...string) sr.Handler {
+ return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response {
dirpath, dir, response := handleDirSpartan(request, fileSystem)
if response != nil {
return response
@@ -77,8 +77,8 @@ func SpartanDirectoryDefault(fileSystem fs.FS, filenames ...string) gus.Handler
//
// The tmeplate may be nil, in which cause DefaultSpartanDirectoryList is used instead. The
// template is then processed with RenderDirectoryListing.
-func SpartanDirectoryListing(filesystem fs.FS, template *template.Template) gus.Handler {
- return gus.HandlerFunc(func(ctx context.Context, request *gus.Request) *gus.Response {
+func SpartanDirectoryListing(filesystem fs.FS, template *template.Template) sr.Handler {
+ return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response {
dirpath, dir, response := handleDirSpartan(request, filesystem)
if response != nil {
return response
@@ -103,7 +103,7 @@ func SpartanDirectoryListing(filesystem fs.FS, template *template.Template) gus.
// DefaultSpartanDirectoryList is a template which renders a reasonable gemtext dir listing.
var DefaultSpartanDirectoryList = DefaultGeminiDirectoryList
-func handleDirSpartan(request *gus.Request, filesystem fs.FS) (string, fs.ReadDirFile, *gus.Response) {
+func handleDirSpartan(request *sr.Request, filesystem fs.FS) (string, fs.ReadDirFile, *sr.Response) {
path, dir, err := ResolveDirectory(request, filesystem)
if err != nil {
return "", nil, spartan.ServerError(err)
diff --git a/contrib/sharedhost/replacement.go b/contrib/sharedhost/replacement.go
index 9267530..9dc3a1e 100644
--- a/contrib/sharedhost/replacement.go
+++ b/contrib/sharedhost/replacement.go
@@ -5,7 +5,7 @@ import (
"crypto/tls"
"net/url"
- "tildegit.org/tjp/gus"
+ sr "tildegit.org/tjp/sliderule"
)
// ReplaceTilde builds a middleware which substitutes a leading '~' in the request path.
@@ -17,9 +17,9 @@ import (
// 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 gus.HandlerFunc(func(ctx context.Context, request *gus.Request) *gus.Response {
+func ReplaceTilde(replacement string) sr.Middleware {
+ return func(inner sr.Handler) sr.Handler {
+ return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response {
if len(request.Path) > 1 && request.Path[0] == '/' && request.Path[1] == '~' {
request = cloneRequest(request)
request.Path = "/" + replacement + request.Path[2:]
@@ -30,8 +30,8 @@ func ReplaceTilde(replacement string) gus.Middleware {
}
}
-func cloneRequest(start *gus.Request) *gus.Request {
- next := &gus.Request{}
+func cloneRequest(start *sr.Request) *sr.Request {
+ next := &sr.Request{}
*next = *start
next.URL = &url.URL{}
diff --git a/contrib/sharedhost/replacement_test.go b/contrib/sharedhost/replacement_test.go
index 67c3754..9fa9161 100644
--- a/contrib/sharedhost/replacement_test.go
+++ b/contrib/sharedhost/replacement_test.go
@@ -7,8 +7,8 @@ import (
"github.com/stretchr/testify/assert"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/contrib/sharedhost"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/contrib/sharedhost"
)
func TestReplaceTilde(t *testing.T) {
@@ -42,10 +42,10 @@ func TestReplaceTilde(t *testing.T) {
originalPath := u.Path
replacer := sharedhost.ReplaceTilde(test.replacement)
- request := &gus.Request{URL: u}
- handler := replacer(gus.HandlerFunc(func(_ context.Context, request *gus.Request) *gus.Response {
+ request := &sr.Request{URL: u}
+ handler := replacer(sr.HandlerFunc(func(_ context.Context, request *sr.Request) *sr.Response {
assert.Equal(t, test.replacedPath, request.Path)
- return &gus.Response{}
+ return &sr.Response{}
}))
handler.Handle(context.Background(), request)
diff --git a/contrib/tlsauth/approver_test.go b/contrib/tlsauth/approver_test.go
index a2af838..d2f4f07 100644
--- a/contrib/tlsauth/approver_test.go
+++ b/contrib/tlsauth/approver_test.go
@@ -8,7 +8,7 @@ import (
"github.com/stretchr/testify/assert"
- "tildegit.org/tjp/gus/contrib/tlsauth"
+ "tildegit.org/tjp/sliderule/contrib/tlsauth"
)
func TestRequireSpecificIdentity(t *testing.T) {
diff --git a/contrib/tlsauth/auth.go b/contrib/tlsauth/auth.go
index 38ec3a3..439d297 100644
--- a/contrib/tlsauth/auth.go
+++ b/contrib/tlsauth/auth.go
@@ -4,11 +4,11 @@ import (
"context"
"crypto/x509"
- "tildegit.org/tjp/gus"
+ sr "tildegit.org/tjp/sliderule"
)
// Identity returns the client certificate for the request or nil if there is none.
-func Identity(request *gus.Request) *x509.Certificate {
+func Identity(request *sr.Request) *x509.Certificate {
if request.TLSState == nil || len(request.TLSState.PeerCertificates) == 0 {
return nil
}
@@ -19,8 +19,8 @@ func Identity(request *gus.Request) *x509.Certificate {
//
// The check requires both that there is a client certificate associated with the
// request and that it passes the provided approver.
-func RequiredAuth(approve Approver) func(context.Context, *gus.Request) bool {
- return func(_ context.Context, request *gus.Request) bool {
+func RequiredAuth(approve Approver) func(context.Context, *sr.Request) bool {
+ return func(_ context.Context, request *sr.Request) bool {
identity := Identity(request)
if identity == nil {
return false
@@ -34,8 +34,8 @@ func RequiredAuth(approve Approver) func(context.Context, *gus.Request) bool {
//
// The check allows through any request with no client certificate, but if
// there is one present then it requires that it pass the provided approver.
-func OptionalAuth(approve Approver) func(context.Context, *gus.Request) bool {
- return func(_ context.Context, request *gus.Request) bool {
+func OptionalAuth(approve Approver) func(context.Context, *sr.Request) bool {
+ return func(_ context.Context, request *sr.Request) bool {
identity := Identity(request)
if identity == nil {
return true
diff --git a/contrib/tlsauth/auth_test.go b/contrib/tlsauth/auth_test.go
index 3cbc106..2a95e1c 100644
--- a/contrib/tlsauth/auth_test.go
+++ b/contrib/tlsauth/auth_test.go
@@ -12,9 +12,9 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/contrib/tlsauth"
- "tildegit.org/tjp/gus/gemini"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/contrib/tlsauth"
+ "tildegit.org/tjp/sliderule/gemini"
)
func TestIdentify(t *testing.T) {
@@ -24,7 +24,7 @@ func TestIdentify(t *testing.T) {
server, client, clientCert := setup(t,
"testdata/server.crt", "testdata/server.key",
"testdata/client1.crt", "testdata/client1.key",
- gus.HandlerFunc(func(_ context.Context, request *gus.Request) *gus.Response {
+ sr.HandlerFunc(func(_ context.Context, request *sr.Request) *sr.Response {
invoked = true
ident := tlsauth.Identity(request)
@@ -51,20 +51,20 @@ func TestRequiredAuth(t *testing.T) {
invoked1 := false
invoked2 := false
- handler1 := gus.HandlerFunc(func(_ context.Context, request *gus.Request) *gus.Response {
+ handler1 := sr.HandlerFunc(func(_ context.Context, request *sr.Request) *sr.Response {
invoked1 = true
return gemini.Success("", &bytes.Buffer{})
})
- handler2 := gus.HandlerFunc(func(_ context.Context, request *gus.Request) *gus.Response {
+ handler2 := sr.HandlerFunc(func(_ context.Context, request *sr.Request) *sr.Response {
invoked2 = true
return gemini.Success("", &bytes.Buffer{})
})
- authMiddleware := gus.Filter(tlsauth.RequiredAuth(tlsauth.Allow), nil)
+ authMiddleware := sr.Filter(tlsauth.RequiredAuth(tlsauth.Allow), nil)
- handler1 = gus.Filter(
- func(_ context.Context, req *gus.Request) bool {
+ handler1 = sr.Filter(
+ func(_ context.Context, req *sr.Request) bool {
return strings.HasPrefix(req.Path, "/one")
},
nil,
@@ -74,7 +74,7 @@ func TestRequiredAuth(t *testing.T) {
server, client, _ := setup(t,
"testdata/server.crt", "testdata/server.key",
"testdata/client1.crt", "testdata/client1.key",
- gus.FallthroughHandler(handler1, handler2),
+ sr.FallthroughHandler(handler1, handler2),
)
go func() {
@@ -94,7 +94,7 @@ func TestOptionalAuth(t *testing.T) {
invoked1 := false
invoked2 := false
- handler1 := gus.HandlerFunc(func(_ context.Context, request *gus.Request) *gus.Response {
+ handler1 := sr.HandlerFunc(func(_ context.Context, request *sr.Request) *sr.Response {
if !strings.HasPrefix(request.Path, "/one") {
return nil
}
@@ -103,13 +103,13 @@ func TestOptionalAuth(t *testing.T) {
return gemini.Success("", &bytes.Buffer{})
})
- handler2 := gus.HandlerFunc(func(_ context.Context, request *gus.Request) *gus.Response {
+ handler2 := sr.HandlerFunc(func(_ context.Context, request *sr.Request) *sr.Response {
invoked2 = true
return gemini.Success("", &bytes.Buffer{})
})
- mw := gus.Filter(tlsauth.OptionalAuth(tlsauth.Reject), nil)
- handler := gus.FallthroughHandler(mw(handler1), mw(handler2))
+ mw := sr.Filter(tlsauth.OptionalAuth(tlsauth.Reject), nil)
+ handler := sr.FallthroughHandler(mw(handler1), mw(handler2))
server, client, _ := setup(t,
"testdata/server.crt", "testdata/server.key",
@@ -136,8 +136,8 @@ func setup(
serverKeyPath string,
clientCertPath string,
clientKeyPath string,
- handler gus.Handler,
-) (gus.Server, gemini.Client, tls.Certificate) {
+ handler sr.Handler,
+) (sr.Server, gemini.Client, tls.Certificate) {
serverTLS, err := gemini.FileTLS(serverCertPath, serverKeyPath)
require.Nil(t, err)
@@ -159,7 +159,7 @@ func setup(
func clientFor(
t *testing.T,
- server gus.Server,
+ server sr.Server,
certPath string,
keyPath string,
) (gemini.Client, tls.Certificate) {
@@ -179,11 +179,11 @@ func clientFor(
}), clientCert
}
-func requestPath(t *testing.T, client gemini.Client, server gus.Server, path string) *gus.Response {
+func requestPath(t *testing.T, client gemini.Client, server sr.Server, path string) *sr.Response {
u, err := url.Parse("gemini://" + server.Address() + path)
require.Nil(t, err)
- response, err := client.RoundTrip(&gus.Request{URL: u})
+ response, err := client.RoundTrip(&sr.Request{URL: u})
require.Nil(t, err)
return response
diff --git a/contrib/tlsauth/gemini.go b/contrib/tlsauth/gemini.go
index 40bee9e..9996595 100644
--- a/contrib/tlsauth/gemini.go
+++ b/contrib/tlsauth/gemini.go
@@ -3,8 +3,8 @@ package tlsauth
import (
"context"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/gemini"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/gemini"
)
// GeminiAuth builds an authentication middleware from approval criteria.
@@ -12,9 +12,9 @@ import (
// If a request does not contain a client certificate it will be rejected
// with a "60 certificate required" response. If the client identity does
// not pass the approver it will be rejected with "62 certificate invalid".
-func GeminiAuth(approver Approver) gus.Middleware {
- return func(inner gus.Handler) gus.Handler {
- return gus.HandlerFunc(func(ctx context.Context, request *gus.Request) *gus.Response {
+func GeminiAuth(approver Approver) sr.Middleware {
+ return func(inner sr.Handler) sr.Handler {
+ return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response {
identity := Identity(request)
if identity == nil {
return geminiMissingCert(ctx, request)
@@ -33,9 +33,9 @@ func GeminiAuth(approver Approver) gus.Middleware {
// If there is no client certificate the request will pass through the middleware.
// It will only be rejected with "62 certificate invalid" if there *is* a client
// certificate, but it fails the approval.
-func GeminiOptionalAuth(approver Approver) gus.Middleware {
- return func(inner gus.Handler) gus.Handler {
- return gus.HandlerFunc(func(ctx context.Context, request *gus.Request) *gus.Response {
+func GeminiOptionalAuth(approver Approver) sr.Middleware {
+ return func(inner sr.Handler) sr.Handler {
+ return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response {
identity := Identity(request)
if identity != nil && !approver(identity) {
return geminiCertNotAuthorized(ctx, request)
@@ -49,10 +49,10 @@ func GeminiOptionalAuth(approver Approver) gus.Middleware {
// GeminiRequireCertificate is a middleware that only requires a client certificate.
var GeminiRequireCertificate = GeminiAuth(Allow)
-func geminiMissingCert(_ context.Context, _ *gus.Request) *gus.Response {
+func geminiMissingCert(_ context.Context, _ *sr.Request) *sr.Response {
return gemini.RequireCert("A client certificate is required.")
}
-func geminiCertNotAuthorized(_ context.Context, _ *gus.Request) *gus.Response {
+func geminiCertNotAuthorized(_ context.Context, _ *sr.Request) *sr.Response {
return gemini.CertAuthFailure("Client certificate not authorized.")
}
diff --git a/contrib/tlsauth/gemini_test.go b/contrib/tlsauth/gemini_test.go
index 7823de6..655307a 100644
--- a/contrib/tlsauth/gemini_test.go
+++ b/contrib/tlsauth/gemini_test.go
@@ -8,38 +8,38 @@ import (
"github.com/stretchr/testify/assert"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/contrib/tlsauth"
- "tildegit.org/tjp/gus/gemini"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/contrib/tlsauth"
+ "tildegit.org/tjp/sliderule/gemini"
)
func TestGeminiAuth(t *testing.T) {
- handler1 := gus.HandlerFunc(func(_ context.Context, request *gus.Request) *gus.Response {
+ handler1 := sr.HandlerFunc(func(_ context.Context, request *sr.Request) *sr.Response {
if !strings.HasPrefix(request.Path, "/one") {
return nil
}
return gemini.Success("", &bytes.Buffer{})
})
- handler2 := gus.HandlerFunc(func(_ context.Context, request *gus.Request) *gus.Response {
+ handler2 := sr.HandlerFunc(func(_ context.Context, request *sr.Request) *sr.Response {
if !strings.HasPrefix(request.Path, "/two") {
return nil
}
return gemini.Success("", &bytes.Buffer{})
})
- handler3 := gus.HandlerFunc(func(_ context.Context, request *gus.Request) *gus.Response {
+ handler3 := sr.HandlerFunc(func(_ context.Context, request *sr.Request) *sr.Response {
if !strings.HasPrefix(request.Path, "/three") {
return nil
}
return gemini.Success("", &bytes.Buffer{})
})
- handler4 := gus.HandlerFunc(func(_ context.Context, request *gus.Request) *gus.Response {
+ handler4 := sr.HandlerFunc(func(_ context.Context, request *sr.Request) *sr.Response {
return gemini.Success("", &bytes.Buffer{})
})
- handler := gus.FallthroughHandler(
+ handler := sr.FallthroughHandler(
tlsauth.GeminiAuth(tlsauth.Allow)(handler1),
tlsauth.GeminiAuth(tlsauth.Allow)(handler2),
tlsauth.GeminiAuth(tlsauth.Reject)(handler3),
@@ -73,8 +73,8 @@ func TestGeminiAuth(t *testing.T) {
}
func TestGeminiOptionalAuth(t *testing.T) {
- pathHandler := func(path string) gus.Handler {
- return gus.HandlerFunc(func(_ context.Context, request *gus.Request) *gus.Response {
+ pathHandler := func(path string) sr.Handler {
+ return sr.HandlerFunc(func(_ context.Context, request *sr.Request) *sr.Response {
if !strings.HasPrefix(request.Path, path) {
return nil
}
@@ -82,7 +82,7 @@ func TestGeminiOptionalAuth(t *testing.T) {
})
}
- handler := gus.FallthroughHandler(
+ handler := sr.FallthroughHandler(
tlsauth.GeminiOptionalAuth(tlsauth.Allow)(pathHandler("/one")),
tlsauth.GeminiOptionalAuth(tlsauth.Allow)(pathHandler("/two")),
tlsauth.GeminiOptionalAuth(tlsauth.Reject)(pathHandler("/three")),
diff --git a/examples/cgi/main.go b/examples/cgi/main.go
index 5c1b9a2..a582c9e 100644
--- a/examples/cgi/main.go
+++ b/examples/cgi/main.go
@@ -7,9 +7,9 @@ import (
"os/signal"
"syscall"
- "tildegit.org/tjp/gus/contrib/cgi"
- "tildegit.org/tjp/gus/gemini"
- "tildegit.org/tjp/gus/logging"
+ "tildegit.org/tjp/sliderule/contrib/cgi"
+ "tildegit.org/tjp/sliderule/gemini"
+ "tildegit.org/tjp/sliderule/logging"
)
func main() {
diff --git a/examples/cowsay/main.go b/examples/cowsay/main.go
index 93f50d8..32ba2ea 100644
--- a/examples/cowsay/main.go
+++ b/examples/cowsay/main.go
@@ -8,9 +8,9 @@ import (
"os"
"os/exec"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/gemini"
- "tildegit.org/tjp/gus/logging"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/gemini"
+ "tildegit.org/tjp/sliderule/logging"
)
func main() {
@@ -36,7 +36,7 @@ func main() {
server.Serve()
}
-var cowsayHandler = gus.HandlerFunc(func(ctx context.Context, req *gus.Request) *gus.Response {
+var cowsayHandler = sr.HandlerFunc(func(ctx context.Context, req *sr.Request) *sr.Response {
// prompt for a query if there is none already
if req.RawQuery == "" {
return gemini.Input("enter a phrase")
diff --git a/examples/fetch/main.go b/examples/fetch/main.go
index 109a042..fccc6cf 100644
--- a/examples/fetch/main.go
+++ b/examples/fetch/main.go
@@ -8,8 +8,8 @@ import (
"os"
"strings"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/gemini"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/gemini"
)
func main() {
@@ -30,7 +30,7 @@ func main() {
}
// parse the URL and build the request
- request := &gus.Request{URL: buildURL()}
+ request := &sr.Request{URL: buildURL()}
// fetch the response
response, err := client.RoundTrip(request)
diff --git a/examples/fileserver/main.go b/examples/fileserver/main.go
index be427a1..d38a450 100644
--- a/examples/fileserver/main.go
+++ b/examples/fileserver/main.go
@@ -5,10 +5,10 @@ import (
"log"
"os"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/contrib/fs"
- "tildegit.org/tjp/gus/gemini"
- "tildegit.org/tjp/gus/logging"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/contrib/fs"
+ "tildegit.org/tjp/sliderule/gemini"
+ "tildegit.org/tjp/sliderule/logging"
)
func main() {
@@ -24,7 +24,7 @@ func main() {
// build the request handler
fileSystem := os.DirFS(".")
// Fallthrough tries each handler in succession until it gets something other than "51 Not Found"
- handler := gus.FallthroughHandler(
+ handler := sr.FallthroughHandler(
// first see if they're fetching a directory and we have <dir>/index.gmi
fs.GeminiDirectoryDefault(fileSystem, "index.gmi"),
// next (still if they requested a directory) build a directory listing response
diff --git a/examples/finger/main.go b/examples/finger/main.go
index 3000dd7..723e3e6 100644
--- a/examples/finger/main.go
+++ b/examples/finger/main.go
@@ -4,8 +4,8 @@ import (
"context"
"log"
- "tildegit.org/tjp/gus/finger"
- "tildegit.org/tjp/gus/logging"
+ "tildegit.org/tjp/sliderule/finger"
+ "tildegit.org/tjp/sliderule/logging"
)
func main() {
diff --git a/examples/gmi2html/main.go b/examples/gmi2html/main.go
index 40c0b8c..b9a0353 100644
--- a/examples/gmi2html/main.go
+++ b/examples/gmi2html/main.go
@@ -4,8 +4,8 @@ import (
"log"
"os"
- "tildegit.org/tjp/gus/gemini/gemtext"
- "tildegit.org/tjp/gus/gemini/gemtext/htmlconv"
+ "tildegit.org/tjp/sliderule/gemini/gemtext"
+ "tildegit.org/tjp/sliderule/gemini/gemtext/htmlconv"
)
func main() {
diff --git a/examples/gmi2md/main.go b/examples/gmi2md/main.go
index df604ba..4a7a714 100644
--- a/examples/gmi2md/main.go
+++ b/examples/gmi2md/main.go
@@ -4,8 +4,8 @@ import (
"log"
"os"
- "tildegit.org/tjp/gus/gemini/gemtext"
- "tildegit.org/tjp/gus/gemini/gemtext/mdconv"
+ "tildegit.org/tjp/sliderule/gemini/gemtext"
+ "tildegit.org/tjp/sliderule/gemini/gemtext/mdconv"
)
func main() {
diff --git a/examples/gopher_fileserver/main.go b/examples/gopher_fileserver/main.go
index 172ca87..244f61b 100644
--- a/examples/gopher_fileserver/main.go
+++ b/examples/gopher_fileserver/main.go
@@ -5,17 +5,17 @@ import (
"log"
"os"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/contrib/cgi"
- "tildegit.org/tjp/gus/contrib/fs"
- "tildegit.org/tjp/gus/gopher"
- "tildegit.org/tjp/gus/logging"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/contrib/cgi"
+ "tildegit.org/tjp/sliderule/contrib/fs"
+ "tildegit.org/tjp/sliderule/gopher"
+ "tildegit.org/tjp/sliderule/logging"
)
func main() {
fileSystem := os.DirFS(".")
- handler := gus.FallthroughHandler(
+ handler := sr.FallthroughHandler(
fs.GopherDirectoryDefault(fileSystem, "index.gophermap"),
fs.GopherDirectoryListing(fileSystem, nil),
cgi.GopherCGIDirectory("/cgi-bin", "./cgi-bin"),
diff --git a/examples/inspectls/main.go b/examples/inspectls/main.go
index 485b84e..5becb71 100644
--- a/examples/inspectls/main.go
+++ b/examples/inspectls/main.go
@@ -12,9 +12,9 @@ import (
"os"
"strings"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/gemini"
- "tildegit.org/tjp/gus/logging"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/gemini"
+ "tildegit.org/tjp/sliderule/logging"
)
func main() {
@@ -54,7 +54,7 @@ func envConfig() (string, string) {
return certfile, keyfile
}
-var inspectHandler = gus.HandlerFunc(func(ctx context.Context, req *gus.Request) *gus.Response {
+var inspectHandler = sr.HandlerFunc(func(ctx context.Context, req *sr.Request) *sr.Response {
// build and return a ```-wrapped description of the connection TLS state
body := "```\n" + displayTLSState(req.TLSState) + "\n```"
return gemini.Success("text/gemini", bytes.NewBufferString(body))
diff --git a/finger/request.go b/finger/request.go
index 833072d..bd2d35a 100644
--- a/finger/request.go
+++ b/finger/request.go
@@ -7,7 +7,7 @@ import (
"net/url"
"strings"
- "tildegit.org/tjp/gus"
+ sr "tildegit.org/tjp/sliderule"
)
// ForwardingDenied is returned in response to requests for forwarding service.
@@ -16,7 +16,7 @@ var ForwardingDenied = errors.New("Finger forwarding service denied.")
// InvalidFingerQuery is sent when a client doesn't properly format the query.
var InvalidFingerQuery = errors.New("Invalid finger query .")
-// ParseRequest builds a gus.Request by reading a finger protocol request.
+// ParseRequest builds a sliderule.Request by reading a finger protocol request.
//
// At the time of writing, there is no firm standard on how to represent finger
// queries as URLs (the finger protocol itself predates URLs entirely), but there
@@ -26,11 +26,11 @@ var InvalidFingerQuery = errors.New("Invalid finger query .")
// - There is an IETF draft:
// https://datatracker.ietf.org/doc/html/draft-ietf-uri-url-finger
//
-// As this function builds a *gus.Request (which is mostly a wrapper around a URL)
+// As this function builds a *sliderule.Request (which is mostly a wrapper around a URL)
// from nothing but an io.Reader, it doesn't have the context of the hostname which
// the receiving server was hosting. So it only has the host component if it
// arrived in the body of the query in the form username@hostname. Bear in mind that
-// in gus handlers, request objects will also carry a reference to the server so
+// in sliderule handlers, request objects will also carry a reference to the server so
// that hostname is always available as request.Server.Hostname().
//
// The primary deviation from the IETF draft is that a query-specified host becomes
@@ -47,7 +47,7 @@ var InvalidFingerQuery = errors.New("Invalid finger query .")
// In accordance with the recommendation of RFC 1288 section 3.2.1
// (https://datatracker.ietf.org/doc/html/rfc1288#section-3.2.1), any queries which
// include a jump-host (user@host1@host2) are rejected with the ForwardingDenied error.
-func ParseRequest(rdr io.Reader) (*gus.Request, error) {
+func ParseRequest(rdr io.Reader) (*sr.Request, error) {
line, err := bufio.NewReader(rdr).ReadString('\n')
if err != nil {
return nil, err
@@ -66,7 +66,7 @@ func ParseRequest(rdr io.Reader) (*gus.Request, error) {
return nil, ForwardingDenied
}
- return &gus.Request{URL: &url.URL{
+ return &sr.Request{URL: &url.URL{
Scheme: "finger",
Host: hostname,
Path: "/" + username,
diff --git a/finger/request_test.go b/finger/request_test.go
index 4b7fcbd..87fbc8c 100644
--- a/finger/request_test.go
+++ b/finger/request_test.go
@@ -8,7 +8,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "tildegit.org/tjp/gus/finger"
+ "tildegit.org/tjp/sliderule/finger"
)
func TestParseRequest(t *testing.T) {
diff --git a/finger/response.go b/finger/response.go
index 07ca9a1..8612f45 100644
--- a/finger/response.go
+++ b/finger/response.go
@@ -5,18 +5,18 @@ import (
"io"
"strings"
- "tildegit.org/tjp/gus"
+ sr "tildegit.org/tjp/sliderule"
)
// Error produces a finger Response containing the error message and Status 1.
-func Error(msg string) *gus.Response {
+func Error(msg string) *sr.Response {
if !strings.HasSuffix(msg, "\r\n") {
msg += "\r\n"
}
- return &gus.Response{Body: bytes.NewBufferString(msg), Status: 1}
+ return &sr.Response{Body: bytes.NewBufferString(msg), Status: 1}
}
// Success produces a finger response with a Status of 0.
-func Success(body io.Reader) *gus.Response {
- return &gus.Response{Body: body}
+func Success(body io.Reader) *sr.Response {
+ return &sr.Response{Body: body}
}
diff --git a/finger/serve.go b/finger/serve.go
index 68b0fa5..5675dcf 100644
--- a/finger/serve.go
+++ b/finger/serve.go
@@ -7,14 +7,14 @@ import (
"net"
"strings"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/internal"
- "tildegit.org/tjp/gus/logging"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/internal"
+ "tildegit.org/tjp/sliderule/logging"
)
type fingerServer struct {
internal.Server
- handler gus.Handler
+ handler sr.Handler
}
func (fs fingerServer) Protocol() string { return "FINGER" }
@@ -25,9 +25,9 @@ func NewServer(
hostname string,
network string,
address string,
- handler gus.Handler,
+ handler sr.Handler,
errLog logging.Logger,
-) (gus.Server, error) {
+) (sr.Server, error) {
fs := &fingerServer{handler: handler}
if strings.IndexByte(hostname, ':') < 0 {
diff --git a/finger/system.go b/finger/system.go
index 4bcf573..aa2cc84 100644
--- a/finger/system.go
+++ b/finger/system.go
@@ -6,15 +6,15 @@ import (
"errors"
"os/exec"
- "tildegit.org/tjp/gus"
+ sr "tildegit.org/tjp/sliderule"
)
// ListingDenied is returned to reject online user listing requests.
var ListingDenied = errors.New("Finger online user list denied.")
// SystemFinger handles finger requests by invoking the finger(1) command-line utility.
-func SystemFinger(allowListings bool) gus.Handler {
- return gus.HandlerFunc(func(ctx context.Context, request *gus.Request) *gus.Response {
+func SystemFinger(allowListings bool) sr.Handler {
+ return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response {
fingerPath, err := exec.LookPath("finger")
if err != nil {
_ = request.Server.LogError(
diff --git a/gemini/client.go b/gemini/client.go
index 4f99078..68c5488 100644
--- a/gemini/client.go
+++ b/gemini/client.go
@@ -7,7 +7,7 @@ import (
"io"
"net"
- "tildegit.org/tjp/gus"
+ sr "tildegit.org/tjp/sliderule"
)
// Client is used for sending gemini requests and parsing gemini responses.
@@ -33,7 +33,7 @@ func NewClient(tlsConf *tls.Config) Client {
//
// This method will not automatically follow redirects or cache permanent failures or
// redirects.
-func (client Client) RoundTrip(request *gus.Request) (*gus.Response, error) {
+func (client Client) RoundTrip(request *sr.Request) (*sr.Response, error) {
if request.Scheme != "gemini" && request.Scheme != "" {
return nil, errors.New("non-gemini protocols not supported")
}
diff --git a/gemini/gemtext/fuzz_test.go b/gemini/gemtext/fuzz_test.go
index f5435c1..f8d7e28 100644
--- a/gemini/gemtext/fuzz_test.go
+++ b/gemini/gemtext/fuzz_test.go
@@ -4,7 +4,7 @@ import (
"bytes"
"testing"
- "tildegit.org/tjp/gus/gemini/gemtext"
+ "tildegit.org/tjp/sliderule/gemini/gemtext"
)
func FuzzParse(f *testing.F) {
diff --git a/gemini/gemtext/htmlconv/convert.go b/gemini/gemtext/htmlconv/convert.go
index 407eb43..101d89a 100644
--- a/gemini/gemtext/htmlconv/convert.go
+++ b/gemini/gemtext/htmlconv/convert.go
@@ -4,8 +4,8 @@ import (
"html/template"
"io"
- "tildegit.org/tjp/gus/gemini/gemtext"
- "tildegit.org/tjp/gus/gemini/gemtext/internal"
+ "tildegit.org/tjp/sliderule/gemini/gemtext"
+ "tildegit.org/tjp/sliderule/gemini/gemtext/internal"
)
// Convert writes markdown to a writer from the provided gemtext document.
diff --git a/gemini/gemtext/htmlconv/convert_test.go b/gemini/gemtext/htmlconv/convert_test.go
index 6e8bfcd..36fb6ed 100644
--- a/gemini/gemtext/htmlconv/convert_test.go
+++ b/gemini/gemtext/htmlconv/convert_test.go
@@ -7,8 +7,8 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "tildegit.org/tjp/gus/gemini/gemtext"
- "tildegit.org/tjp/gus/gemini/gemtext/htmlconv"
+ "tildegit.org/tjp/sliderule/gemini/gemtext"
+ "tildegit.org/tjp/sliderule/gemini/gemtext/htmlconv"
)
var gmiDoc = `
diff --git a/gemini/gemtext/internal/templates.go b/gemini/gemtext/internal/templates.go
index 08bc66c..3ca7224 100644
--- a/gemini/gemtext/internal/templates.go
+++ b/gemini/gemtext/internal/templates.go
@@ -5,7 +5,7 @@ import (
"net/url"
"text/template"
- "tildegit.org/tjp/gus/gemini/gemtext"
+ "tildegit.org/tjp/sliderule/gemini/gemtext"
)
var Renderers = map[gemtext.LineType]string{
diff --git a/gemini/gemtext/mdconv/convert.go b/gemini/gemtext/mdconv/convert.go
index c2f434d..3416671 100644
--- a/gemini/gemtext/mdconv/convert.go
+++ b/gemini/gemtext/mdconv/convert.go
@@ -4,8 +4,8 @@ import (
"io"
"text/template"
- "tildegit.org/tjp/gus/gemini/gemtext"
- "tildegit.org/tjp/gus/gemini/gemtext/internal"
+ "tildegit.org/tjp/sliderule/gemini/gemtext"
+ "tildegit.org/tjp/sliderule/gemini/gemtext/internal"
)
// Convert writes markdown to a writer from the provided gemtext document.
diff --git a/gemini/gemtext/mdconv/convert_test.go b/gemini/gemtext/mdconv/convert_test.go
index c8fd53c..9ada8b4 100644
--- a/gemini/gemtext/mdconv/convert_test.go
+++ b/gemini/gemtext/mdconv/convert_test.go
@@ -8,8 +8,8 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "tildegit.org/tjp/gus/gemini/gemtext"
- "tildegit.org/tjp/gus/gemini/gemtext/mdconv"
+ "tildegit.org/tjp/sliderule/gemini/gemtext"
+ "tildegit.org/tjp/sliderule/gemini/gemtext/mdconv"
)
var gmiDoc = `
diff --git a/gemini/gemtext/parse_line_test.go b/gemini/gemtext/parse_line_test.go
index 82b0c28..9073df0 100644
--- a/gemini/gemtext/parse_line_test.go
+++ b/gemini/gemtext/parse_line_test.go
@@ -3,7 +3,7 @@ package gemtext_test
import (
"testing"
- "tildegit.org/tjp/gus/gemini/gemtext"
+ "tildegit.org/tjp/sliderule/gemini/gemtext"
)
func TestParseLinkLine(t *testing.T) {
diff --git a/gemini/gemtext/parse_test.go b/gemini/gemtext/parse_test.go
index 6b35431..90d2c75 100644
--- a/gemini/gemtext/parse_test.go
+++ b/gemini/gemtext/parse_test.go
@@ -7,7 +7,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "tildegit.org/tjp/gus/gemini/gemtext"
+ "tildegit.org/tjp/sliderule/gemini/gemtext"
)
func TestParse(t *testing.T) {
diff --git a/gemini/request.go b/gemini/request.go
index 5220952..51aaae5 100644
--- a/gemini/request.go
+++ b/gemini/request.go
@@ -6,7 +6,7 @@ import (
"io"
"net/url"
- "tildegit.org/tjp/gus"
+ sr "tildegit.org/tjp/sliderule"
)
// InvalidRequestLineEnding indicates that a gemini request didn't end with "\r\n".
@@ -15,7 +15,7 @@ var InvalidRequestLineEnding = errors.New("invalid request line ending")
// ParseRequest parses a single gemini request from a reader.
//
// If the reader argument is a *bufio.Reader, it will only read a single line from it.
-func ParseRequest(rdr io.Reader) (*gus.Request, error) {
+func ParseRequest(rdr io.Reader) (*sr.Request, error) {
bufrdr, ok := rdr.(*bufio.Reader)
if !ok {
bufrdr = bufio.NewReader(rdr)
@@ -39,5 +39,19 @@ func ParseRequest(rdr io.Reader) (*gus.Request, error) {
u.Scheme = "gemini"
}
- return &gus.Request{URL: u}, nil
+ return &sr.Request{URL: u}, nil
+}
+
+// GetTitanRequestBody fetches the request body from a titan request.
+//
+// It returns nil if the argument is not a titan request or it otherwise
+// does not have a request body set.
+func GetTitanRequestBody(request *sr.Request) io.Reader {
+ if request.Scheme != "titan" {
+ return nil
+ }
+ if rdr, ok := request.Meta.(io.Reader); ok {
+ return rdr
+ }
+ return nil
}
diff --git a/gemini/request_test.go b/gemini/request_test.go
index 1da24f7..a2b1830 100644
--- a/gemini/request_test.go
+++ b/gemini/request_test.go
@@ -4,7 +4,7 @@ import (
"bytes"
"testing"
- "tildegit.org/tjp/gus/gemini"
+ "tildegit.org/tjp/sliderule/gemini"
)
func TestParseRequest(t *testing.T) {
diff --git a/gemini/response.go b/gemini/response.go
index b8797da..9d4ede1 100644
--- a/gemini/response.go
+++ b/gemini/response.go
@@ -8,7 +8,7 @@ import (
"strconv"
"sync"
- "tildegit.org/tjp/gus"
+ sr "tildegit.org/tjp/sliderule"
)
// ResponseCategory represents the various types of gemini responses.
@@ -43,32 +43,32 @@ const (
ResponseCategoryCertificateRequired
)
-func ResponseCategoryForStatus(status gus.Status) ResponseCategory {
+func ResponseCategoryForStatus(status sr.Status) ResponseCategory {
return ResponseCategory(status / 10)
}
const (
// StatusInput indicates a required query parameter at the requested URL.
- StatusInput gus.Status = gus.Status(ResponseCategoryInput) + iota
+ StatusInput sr.Status = sr.Status(ResponseCategoryInput) + iota
// StatusSensitiveInput indicates a sensitive query parameter is required.
StatusSensitiveInput
)
const (
// StatusSuccess is a successful response.
- StatusSuccess = gus.Status(ResponseCategorySuccess) + iota
+ StatusSuccess = sr.Status(ResponseCategorySuccess) + iota
)
const (
// StatusTemporaryRedirect indicates a temporary redirect to another URL.
- StatusTemporaryRedirect = gus.Status(ResponseCategoryRedirect) + iota
+ StatusTemporaryRedirect = sr.Status(ResponseCategoryRedirect) + iota
// StatusPermanentRedirect indicates that the resource should always be requested at the new URL.
StatusPermanentRedirect
)
const (
// StatusTemporaryFailure indicates that the request failed and there is no response body.
- StatusTemporaryFailure = gus.Status(ResponseCategoryTemporaryFailure) + iota
+ StatusTemporaryFailure = sr.Status(ResponseCategoryTemporaryFailure) + iota
// StatusServerUnavailable occurs when the server is unavailable due to overload or maintenance.
StatusServerUnavailable
// StatusCGIError is the result of a failure of a CGI script.
@@ -84,7 +84,7 @@ const (
const (
// StatusPermanentFailure is a server failure which should be expected to continue indefinitely.
- StatusPermanentFailure = gus.Status(ResponseCategoryPermanentFailure) + iota
+ StatusPermanentFailure = sr.Status(ResponseCategoryPermanentFailure) + iota
// StatusNotFound means the resource doesn't exist but it may in the future.
StatusNotFound
// StatusGone occurs when a resource will not be available any longer.
@@ -92,12 +92,12 @@ const (
// StatusProxyRequestRefused means the server is unwilling to act as a proxy for the resource.
StatusProxyRequestRefused
// StatusBadRequest indicates that the request was malformed somehow.
- StatusBadRequest = gus.Status(ResponseCategoryPermanentFailure) + 9
+ StatusBadRequest = sr.Status(ResponseCategoryPermanentFailure) + 9
)
const (
// StatusClientCertificateRequired is returned when a certificate was required but not provided.
- StatusClientCertificateRequired = gus.Status(ResponseCategoryCertificateRequired) + iota
+ StatusClientCertificateRequired = sr.Status(ResponseCategoryCertificateRequired) + iota
// StatusCertificateNotAuthorized means the certificate doesn't grant access to the requested resource.
StatusCertificateNotAuthorized
// StatusCertificateNotValid means the provided client certificate is invalid.
@@ -105,24 +105,24 @@ const (
)
// Input builds an input-prompting response.
-func Input(prompt string) *gus.Response {
- return &gus.Response{
+func Input(prompt string) *sr.Response {
+ return &sr.Response{
Status: StatusInput,
Meta: prompt,
}
}
// SensitiveInput builds a password-prompting response.
-func SensitiveInput(prompt string) *gus.Response {
- return &gus.Response{
+func SensitiveInput(prompt string) *sr.Response {
+ return &sr.Response{
Status: StatusSensitiveInput,
Meta: prompt,
}
}
// Success builds a success response with resource body.
-func Success(mediatype string, body io.Reader) *gus.Response {
- return &gus.Response{
+func Success(mediatype string, body io.Reader) *sr.Response {
+ return &sr.Response{
Status: StatusSuccess,
Meta: mediatype,
Body: body,
@@ -130,120 +130,120 @@ func Success(mediatype string, body io.Reader) *gus.Response {
}
// Redirect builds a redirect response.
-func Redirect(url string) *gus.Response {
- return &gus.Response{
+func Redirect(url string) *sr.Response {
+ return &sr.Response{
Status: StatusTemporaryRedirect,
Meta: url,
}
}
// PermanentRedirect builds a response with a permanent redirect.
-func PermanentRedirect(url string) *gus.Response {
- return &gus.Response{
+func PermanentRedirect(url string) *sr.Response {
+ return &sr.Response{
Status: StatusPermanentRedirect,
Meta: url,
}
}
// Failure builds a temporary failure response from an error.
-func Failure(err error) *gus.Response {
- return &gus.Response{
+func Failure(err error) *sr.Response {
+ return &sr.Response{
Status: StatusTemporaryFailure,
Meta: err.Error(),
}
}
// Unavailable build a "server unavailable" response.
-func Unavailable(msg string) *gus.Response {
- return &gus.Response{
+func Unavailable(msg string) *sr.Response {
+ return &sr.Response{
Status: StatusServerUnavailable,
Meta: msg,
}
}
// CGIError builds a "cgi error" response.
-func CGIError(err string) *gus.Response {
- return &gus.Response{
+func CGIError(err string) *sr.Response {
+ return &sr.Response{
Status: StatusCGIError,
Meta: err,
}
}
// ProxyError builds a proxy error response.
-func ProxyError(msg string) *gus.Response {
- return &gus.Response{
+func ProxyError(msg string) *sr.Response {
+ return &sr.Response{
Status: StatusProxyError,
Meta: msg,
}
}
// SlowDown builds a "slow down" response with the number of seconds until the resource is available.
-func SlowDown(seconds int) *gus.Response {
- return &gus.Response{
+func SlowDown(seconds int) *sr.Response {
+ return &sr.Response{
Status: StatusSlowDown,
Meta: strconv.Itoa(seconds),
}
}
// PermanentFailure builds a "permanent failure" from an error.
-func PermanentFailure(err error) *gus.Response {
- return &gus.Response{
+func PermanentFailure(err error) *sr.Response {
+ return &sr.Response{
Status: StatusPermanentFailure,
Meta: err.Error(),
}
}
// NotFound builds a "resource not found" response.
-func NotFound(msg string) *gus.Response {
- return &gus.Response{
+func NotFound(msg string) *sr.Response {
+ return &sr.Response{
Status: StatusNotFound,
Meta: msg,
}
}
// Gone builds a "resource gone" response.
-func Gone(msg string) *gus.Response {
- return &gus.Response{
+func Gone(msg string) *sr.Response {
+ return &sr.Response{
Status: StatusGone,
Meta: msg,
}
}
// RefuseProxy builds a "proxy request refused" response.
-func RefuseProxy(msg string) *gus.Response {
- return &gus.Response{
+func RefuseProxy(msg string) *sr.Response {
+ return &sr.Response{
Status: StatusProxyRequestRefused,
Meta: msg,
}
}
// BadRequest builds a "bad request" response.
-func BadRequest(msg string) *gus.Response {
- return &gus.Response{
+func BadRequest(msg string) *sr.Response {
+ return &sr.Response{
Status: StatusBadRequest,
Meta: msg,
}
}
// RequireCert builds a "client certificate required" response.
-func RequireCert(msg string) *gus.Response {
- return &gus.Response{
+func RequireCert(msg string) *sr.Response {
+ return &sr.Response{
Status: StatusClientCertificateRequired,
Meta: msg,
}
}
// CertAuthFailure builds a "certificate not authorized" response.
-func CertAuthFailure(msg string) *gus.Response {
- return &gus.Response{
+func CertAuthFailure(msg string) *sr.Response {
+ return &sr.Response{
Status: StatusCertificateNotAuthorized,
Meta: msg,
}
}
// CertInvalid builds a "client certificate not valid" response.
-func CertInvalid(msg string) *gus.Response {
- return &gus.Response{
+func CertInvalid(msg string) *sr.Response {
+ return &sr.Response{
Status: StatusCertificateNotValid,
Meta: msg,
}
@@ -258,7 +258,7 @@ var InvalidResponseHeaderLine = errors.New("Invalid response header line.")
// ParseResponse parses a complete gemini response from a reader.
//
// The reader must contain only one gemini response.
-func ParseResponse(rdr io.Reader) (*gus.Response, error) {
+func ParseResponse(rdr io.Reader) (*sr.Response, error) {
bufrdr := bufio.NewReader(rdr)
hdrLine, err := bufrdr.ReadBytes('\n')
@@ -278,14 +278,14 @@ func ParseResponse(rdr io.Reader) (*gus.Response, error) {
return nil, InvalidResponseHeaderLine
}
- return &gus.Response{
- Status: gus.Status(status),
+ return &sr.Response{
+ Status: sr.Status(status),
Meta: string(hdrLine[3:]),
Body: bufrdr,
}, nil
}
-func NewResponseReader(response *gus.Response) gus.ResponseReader {
+func NewResponseReader(response *sr.Response) sr.ResponseReader {
return &responseReader{
Response: response,
once: &sync.Once{},
@@ -293,7 +293,7 @@ func NewResponseReader(response *gus.Response) gus.ResponseReader {
}
type responseReader struct {
- *gus.Response
+ *sr.Response
reader io.Reader
once *sync.Once
}
diff --git a/gemini/response_test.go b/gemini/response_test.go
index 9287d71..00166dd 100644
--- a/gemini/response_test.go
+++ b/gemini/response_test.go
@@ -6,15 +6,15 @@ import (
"io"
"testing"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/gemini"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/gemini"
)
func TestBuildResponses(t *testing.T) {
table := []struct {
name string
- response *gus.Response
- status gus.Status
+ response *sr.Response
+ status sr.Status
meta string
body string
}{
@@ -154,7 +154,7 @@ func TestBuildResponses(t *testing.T) {
func TestParseResponses(t *testing.T) {
table := []struct {
input string
- status gus.Status
+ status sr.Status
meta string
body string
err error
@@ -233,7 +233,7 @@ func TestParseResponses(t *testing.T) {
func TestResponseClose(t *testing.T) {
body := &rdCloser{Buffer: bytes.NewBufferString("the body here")}
- resp := &gus.Response{
+ resp := &sr.Response{
Status: gemini.StatusSuccess,
Meta: "text/gemini",
Body: body,
@@ -247,7 +247,7 @@ func TestResponseClose(t *testing.T) {
t.Error("response body was not closed by response.Close()")
}
- resp = &gus.Response{
+ resp = &sr.Response{
Status: gemini.StatusInput,
Meta: "give me more",
}
@@ -270,8 +270,8 @@ func (rc *rdCloser) Close() error {
func TestResponseWriteTo(t *testing.T) {
// invariant under test: WriteTo() sends the same bytes as Read()
- clone := func(resp *gus.Response) *gus.Response {
- other := &gus.Response{
+ clone := func(resp *sr.Response) *sr.Response {
+ other := &sr.Response{
Status: resp.Status,
Meta: resp.Meta,
}
@@ -297,7 +297,7 @@ func TestResponseWriteTo(t *testing.T) {
table := []struct {
name string
- response *gus.Response
+ response *sr.Response
}{
{
name: "simple success",
diff --git a/gemini/roundtrip_test.go b/gemini/roundtrip_test.go
index e8d2b48..67b1ae0 100644
--- a/gemini/roundtrip_test.go
+++ b/gemini/roundtrip_test.go
@@ -12,15 +12,15 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/gemini"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/gemini"
)
func TestRoundTrip(t *testing.T) {
tlsConf, err := gemini.FileTLS("./testdata/server.crt", "./testdata/server.key")
require.Nil(t, err)
- handler := gus.HandlerFunc(func(ctx context.Context, req *gus.Request) *gus.Response {
+ handler := sr.HandlerFunc(func(ctx context.Context, req *sr.Request) *sr.Response {
return gemini.Success("text/gemini", bytes.NewBufferString("you've found my page"))
})
@@ -36,7 +36,7 @@ func TestRoundTrip(t *testing.T) {
require.Nil(t, err)
cli := gemini.NewClient(testClientTLS())
- response, err := cli.RoundTrip(&gus.Request{URL: u})
+ response, err := cli.RoundTrip(&sr.Request{URL: u})
require.Nil(t, err)
assert.Equal(t, gemini.StatusSuccess, response.Status)
@@ -54,10 +54,10 @@ func TestTitanRequest(t *testing.T) {
require.Nil(t, err)
invoked := false
- handler := gus.HandlerFunc(func(ctx context.Context, request *gus.Request) *gus.Response {
+ handler := sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response {
invoked = true
- body := ctx.Value(gemini.TitanRequestBody)
+ body := gemini.GetTitanRequestBody(request)
if !assert.NotNil(t, body) {
return gemini.Success("", nil)
}
diff --git a/gemini/serve.go b/gemini/serve.go
index 2f93153..01e186f 100644
--- a/gemini/serve.go
+++ b/gemini/serve.go
@@ -11,23 +11,17 @@ import (
"strconv"
"strings"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/internal"
- "tildegit.org/tjp/gus/logging"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/internal"
+ "tildegit.org/tjp/sliderule/logging"
)
type titanRequestBodyKey struct{}
-// TitanRequestBody is the key set in a handler's context for titan requests.
-//
-// When this key is present in the context (request.URL.Scheme will be "titan"), the
-// corresponding value is a *bufio.Reader from which the request body can be read.
-var TitanRequestBody = titanRequestBodyKey{}
-
type server struct {
internal.Server
- handler gus.Handler
+ handler sr.Handler
}
func (s server) Protocol() string { return "GEMINI" }
@@ -38,10 +32,10 @@ func NewServer(
hostname string,
network string,
address string,
- handler gus.Handler,
+ handler sr.Handler,
errorLog logging.Logger,
tlsConfig *tls.Config,
-) (gus.Server, error) {
+) (sr.Server, error) {
s := &server{handler: handler}
if strings.IndexByte(hostname, ':') < 0 {
@@ -62,7 +56,7 @@ func NewServer(
func (s *server) handleConn(conn net.Conn) {
buf := bufio.NewReader(conn)
- var response *gus.Response
+ var response *sr.Response
request, err := ParseRequest(buf)
if err != nil {
response = BadRequest(err.Error())
@@ -79,11 +73,7 @@ func (s *server) handleConn(conn net.Conn) {
if request.Scheme == "titan" {
len, err := sizeParam(request.Path)
if err == nil {
- ctx = context.WithValue(
- ctx,
- TitanRequestBody,
- io.LimitReader(buf, int64(len)),
- )
+ request.Meta = io.LimitReader(buf, int64(len))
}
}
@@ -125,9 +115,9 @@ func sizeParam(path string) (int, error) {
// Optionally, it will also allow through titan:// requests.
//
// Filtered requests will be turned away with a 53 response "proxy request refused".
-func GeminiOnly(allowTitan bool) gus.Middleware {
- return func(inner gus.Handler) gus.Handler {
- return gus.HandlerFunc(func(ctx context.Context, request *gus.Request) *gus.Response {
+func GeminiOnly(allowTitan bool) sr.Middleware {
+ return func(inner sr.Handler) sr.Handler {
+ return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response {
if request.Scheme == "gemini" || (allowTitan && request.Scheme == "titan") {
return inner.Handle(ctx, request)
}
diff --git a/go.mod b/go.mod
index 900e959..27bb1f9 100644
--- a/go.mod
+++ b/go.mod
@@ -1,4 +1,4 @@
-module tildegit.org/tjp/gus
+module tildegit.org/tjp/sliderule
go 1.19
diff --git a/gopher/client.go b/gopher/client.go
index 8f5ca81..fad9413 100644
--- a/gopher/client.go
+++ b/gopher/client.go
@@ -6,7 +6,7 @@ import (
"io"
"net"
- "tildegit.org/tjp/gus"
+ sr "tildegit.org/tjp/sliderule"
)
// Client is used for sending gopher requests and producing the responses.
@@ -17,7 +17,7 @@ import (
type Client struct{}
// RoundTrip sends a single gopher request and returns its response.
-func (c Client) RoundTrip(request *gus.Request) (*gus.Response, error) {
+func (c Client) RoundTrip(request *sr.Request) (*sr.Response, error) {
if request.Scheme != "gopher" && request.Scheme != "" {
return nil, errors.New("non-gopher protocols not supported")
}
@@ -51,5 +51,5 @@ func (c Client) RoundTrip(request *gus.Request) (*gus.Response, error) {
return nil, err
}
- return &gus.Response{Body: bytes.NewBuffer(response)}, nil
+ return &sr.Response{Body: bytes.NewBuffer(response)}, nil
}
diff --git a/gopher/gophermap/parse.go b/gopher/gophermap/parse.go
index 302aef0..17fe833 100644
--- a/gopher/gophermap/parse.go
+++ b/gopher/gophermap/parse.go
@@ -7,8 +7,8 @@ import (
"fmt"
"io"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/gopher"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/gopher"
)
// Parse reads a gophermap document from a reader.
@@ -30,7 +30,7 @@ func Parse(input io.Reader) (gopher.MapDocument, error) {
return nil, InvalidLine(num)
}
- item := gopher.MapItem{Type: gus.Status(line[0])}
+ item := gopher.MapItem{Type: sr.Status(line[0])}
spl := bytes.Split(line[1:len(line)-2], []byte{'\t'})
if len(spl) != 4 {
diff --git a/gopher/gophermap/parse_test.go b/gopher/gophermap/parse_test.go
index 0e5c09e..51a430e 100644
--- a/gopher/gophermap/parse_test.go
+++ b/gopher/gophermap/parse_test.go
@@ -8,8 +8,8 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "tildegit.org/tjp/gus/gopher"
- "tildegit.org/tjp/gus/gopher/gophermap"
+ "tildegit.org/tjp/sliderule/gopher"
+ "tildegit.org/tjp/sliderule/gopher/gophermap"
)
func TestParse(t *testing.T) {
diff --git a/gopher/request.go b/gopher/request.go
index ef68438..4125af3 100644
--- a/gopher/request.go
+++ b/gopher/request.go
@@ -8,11 +8,11 @@ import (
"path"
"strings"
- "tildegit.org/tjp/gus"
+ sr "tildegit.org/tjp/sliderule"
)
-// ParseRequest parses a gopher protocol request into a gus.Request object.
-func ParseRequest(rdr io.Reader) (*gus.Request, error) {
+// ParseRequest parses a gopher protocol request into a sliderule.Request object.
+func ParseRequest(rdr io.Reader) (*sr.Request, error) {
selector, search, err := readFullRequest(rdr)
if err != nil {
return nil, err
@@ -22,7 +22,7 @@ func ParseRequest(rdr io.Reader) (*gus.Request, error) {
selector = "/" + selector
}
- return &gus.Request{
+ return &sr.Request{
URL: &url.URL{
Scheme: "gopher",
Path: path.Clean(strings.TrimSuffix(selector, "\r\n")),
diff --git a/gopher/request_test.go b/gopher/request_test.go
index 1ab7801..74030c6 100644
--- a/gopher/request_test.go
+++ b/gopher/request_test.go
@@ -7,7 +7,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "tildegit.org/tjp/gus/gopher"
+ "tildegit.org/tjp/sliderule/gopher"
)
func TestParseRequest(t *testing.T) {
diff --git a/gopher/response.go b/gopher/response.go
index c600b10..566623f 100644
--- a/gopher/response.go
+++ b/gopher/response.go
@@ -6,49 +6,49 @@ import (
"io"
"sync"
- "tildegit.org/tjp/gus"
+ sr "tildegit.org/tjp/sliderule"
)
// The Canonical gopher item types.
const (
- TextFileType gus.Status = '0'
- MenuType gus.Status = '1'
- CSOPhoneBookType gus.Status = '2'
- ErrorType gus.Status = '3'
- MacBinHexType gus.Status = '4'
- DosBinType gus.Status = '5'
- UuencodedType gus.Status = '6'
- SearchType gus.Status = '7'
- TelnetSessionType gus.Status = '8'
- BinaryFileType gus.Status = '9'
- MirrorServerType gus.Status = '+'
- GifFileType gus.Status = 'g'
- ImageFileType gus.Status = 'I'
- Telnet3270Type gus.Status = 'T'
+ TextFileType sr.Status = '0'
+ MenuType sr.Status = '1'
+ CSOPhoneBookType sr.Status = '2'
+ ErrorType sr.Status = '3'
+ MacBinHexType sr.Status = '4'
+ DosBinType sr.Status = '5'
+ UuencodedType sr.Status = '6'
+ SearchType sr.Status = '7'
+ TelnetSessionType sr.Status = '8'
+ BinaryFileType sr.Status = '9'
+ MirrorServerType sr.Status = '+'
+ GifFileType sr.Status = 'g'
+ ImageFileType sr.Status = 'I'
+ Telnet3270Type sr.Status = 'T'
)
// The gopher+ types.
const (
- BitmapType gus.Status = ':'
- MovieFileType gus.Status = ';'
- SoundFileType gus.Status = '<'
+ BitmapType sr.Status = ':'
+ MovieFileType sr.Status = ';'
+ SoundFileType sr.Status = '<'
)
// The various non-canonical gopher types.
const (
- DocumentType gus.Status = 'd'
- HTMLType gus.Status = 'h'
- InfoMessageType gus.Status = 'i'
- PngImageFileType gus.Status = 'p'
- RtfDocumentType gus.Status = 'r'
- WavSoundFileType gus.Status = 's'
- PdfDocumentType gus.Status = 'P'
- XmlDocumentType gus.Status = 'X'
+ DocumentType sr.Status = 'd'
+ HTMLType sr.Status = 'h'
+ InfoMessageType sr.Status = 'i'
+ PngImageFileType sr.Status = 'p'
+ RtfDocumentType sr.Status = 'r'
+ WavSoundFileType sr.Status = 's'
+ PdfDocumentType sr.Status = 'P'
+ XmlDocumentType sr.Status = 'X'
)
// MapItem is a single item in a gophermap.
type MapItem struct {
- Type gus.Status
+ Type sr.Status
Display string
Selector string
Hostname string
@@ -70,8 +70,8 @@ func (mi MapItem) String() string {
// Response builds a response which contains just this single MapItem.
//
// Meta in the response will be a pointer to the MapItem.
-func (mi *MapItem) Response() *gus.Response {
- return &gus.Response{
+func (mi *MapItem) Response() *sr.Response {
+ return &sr.Response{
Status: mi.Type,
Meta: &mi,
Body: bytes.NewBufferString(mi.String() + ".\r\n"),
@@ -89,8 +89,8 @@ func (md MapDocument) String() string {
// Response builds a gopher response containing the gophermap.
//
// Meta will be the MapDocument itself.
-func (md MapDocument) Response() *gus.Response {
- return &gus.Response{
+func (md MapDocument) Response() *sr.Response {
+ return &sr.Response{
Status: DocumentType,
Meta: md,
Body: md.serialize(),
@@ -119,12 +119,12 @@ func Error(err error) *MapItem {
// File builds a minimal response delivering a file's contents.
//
// Meta is nil and Status is 0 in this response.
-func File(status gus.Status, contents io.Reader) *gus.Response {
- return &gus.Response{Status: status, Body: contents}
+func File(status sr.Status, contents io.Reader) *sr.Response {
+ return &sr.Response{Status: status, Body: contents}
}
// NewResponseReader produces a reader which supports reading gopher protocol responses.
-func NewResponseReader(response *gus.Response) gus.ResponseReader {
+func NewResponseReader(response *sr.Response) sr.ResponseReader {
return &responseReader{
Response: response,
once: &sync.Once{},
@@ -132,7 +132,7 @@ func NewResponseReader(response *gus.Response) gus.ResponseReader {
}
type responseReader struct {
- *gus.Response
+ *sr.Response
reader io.Reader
once *sync.Once
}
diff --git a/gopher/serve.go b/gopher/serve.go
index 572fa55..bad7935 100644
--- a/gopher/serve.go
+++ b/gopher/serve.go
@@ -8,14 +8,14 @@ import (
"net"
"strings"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/internal"
- "tildegit.org/tjp/gus/logging"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/internal"
+ "tildegit.org/tjp/sliderule/logging"
)
type gopherServer struct {
internal.Server
- handler gus.Handler
+ handler sr.Handler
}
func (gs gopherServer) Protocol() string { return "GOPHER" }
@@ -26,9 +26,9 @@ func NewServer(
hostname string,
network string,
address string,
- handler gus.Handler,
+ handler sr.Handler,
errLog logging.Logger,
-) (gus.Server, error) {
+) (sr.Server, error) {
gs := &gopherServer{handler: handler}
if strings.IndexByte(hostname, ':') < 0 {
@@ -45,7 +45,7 @@ func NewServer(
}
func (gs *gopherServer) handleConn(conn net.Conn) {
- var response *gus.Response
+ var response *sr.Response
request, err := ParseRequest(conn)
if err != nil {
response = Error(errors.New("Malformed request.")).Response()
diff --git a/handler.go b/handler.go
index 7b784ed..bf6a21d 100644
--- a/handler.go
+++ b/handler.go
@@ -1,4 +1,4 @@
-package gus
+package sliderule
import "context"
diff --git a/handler_test.go b/handler_test.go
index 18ef562..048e8be 100644
--- a/handler_test.go
+++ b/handler_test.go
@@ -1,4 +1,4 @@
-package gus_test
+package sliderule_test
import (
"bytes"
@@ -8,33 +8,33 @@ import (
"strings"
"testing"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/gemini"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/gemini"
)
func TestFallthrough(t *testing.T) {
- h1 := gus.HandlerFunc(func(ctx context.Context, req *gus.Request) *gus.Response {
+ h1 := sr.HandlerFunc(func(ctx context.Context, req *sr.Request) *sr.Response {
if req.Path == "/one" {
return gemini.Success("text/gemini", bytes.NewBufferString("one"))
}
return nil
})
- h2 := gus.HandlerFunc(func(ctx context.Context, req *gus.Request) *gus.Response {
+ h2 := sr.HandlerFunc(func(ctx context.Context, req *sr.Request) *sr.Response {
if req.Path == "/two" {
return gemini.Success("text/gemini", bytes.NewBufferString("two"))
}
return nil
})
- fth := gus.FallthroughHandler(h1, h2)
+ fth := sr.FallthroughHandler(h1, h2)
u, err := url.Parse("gemini://test.local/one")
if err != nil {
t.Fatalf("url.Parse: %s", err.Error())
}
- resp := fth.Handle(context.Background(), &gus.Request{URL: u})
+ resp := fth.Handle(context.Background(), &sr.Request{URL: u})
if resp.Status != gemini.StatusSuccess {
t.Errorf("expected status %d, got %d", gemini.StatusSuccess, resp.Status)
@@ -57,7 +57,7 @@ func TestFallthrough(t *testing.T) {
t.Fatalf("url.Parse: %s", err.Error())
}
- resp = fth.Handle(context.Background(), &gus.Request{URL: u})
+ resp = fth.Handle(context.Background(), &sr.Request{URL: u})
if resp.Status != gemini.StatusSuccess {
t.Errorf("expected status %d, got %d", gemini.StatusSuccess, resp.Status)
@@ -80,7 +80,7 @@ func TestFallthrough(t *testing.T) {
t.Fatalf("url.Parse: %s", err.Error())
}
- resp = fth.Handle(context.Background(), &gus.Request{URL: u})
+ resp = fth.Handle(context.Background(), &sr.Request{URL: u})
if resp != nil {
t.Errorf("expected nil, got %+v", resp)
@@ -88,20 +88,20 @@ func TestFallthrough(t *testing.T) {
}
func TestFilter(t *testing.T) {
- pred := func(ctx context.Context, req *gus.Request) bool {
+ pred := func(ctx context.Context, req *sr.Request) bool {
return strings.HasPrefix(req.Path, "/allow")
}
- base := gus.HandlerFunc(func(ctx context.Context, req *gus.Request) *gus.Response {
+ base := sr.HandlerFunc(func(ctx context.Context, req *sr.Request) *sr.Response {
return gemini.Success("text/gemini", bytes.NewBufferString("allowed!"))
})
- handler := gus.Filter(pred, nil)(base)
+ handler := sr.Filter(pred, nil)(base)
u, err := url.Parse("gemini://test.local/allow/please")
if err != nil {
t.Fatalf("url.Parse: %s", err.Error())
}
- resp := handler.Handle(context.Background(), &gus.Request{URL: u})
+ resp := handler.Handle(context.Background(), &sr.Request{URL: u})
if resp.Status != gemini.StatusSuccess {
t.Errorf("expected status %d, got %d", gemini.StatusSuccess, resp.Status)
}
@@ -111,7 +111,7 @@ func TestFilter(t *testing.T) {
t.Fatalf("url.Parse: %s", err.Error())
}
- resp = handler.Handle(context.Background(), &gus.Request{URL: u})
+ resp = handler.Handle(context.Background(), &sr.Request{URL: u})
if resp != nil {
t.Errorf("expected nil, got %+v", resp)
}
diff --git a/internal/pathtree_test.go b/internal/pathtree_test.go
index 11f6848..e152e85 100644
--- a/internal/pathtree_test.go
+++ b/internal/pathtree_test.go
@@ -7,7 +7,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "tildegit.org/tjp/gus/internal"
+ "tildegit.org/tjp/sliderule/internal"
)
func TestPathTree(t *testing.T) {
diff --git a/logging/middleware.go b/logging/middleware.go
index 4e23c1e..3b68c15 100644
--- a/logging/middleware.go
+++ b/logging/middleware.go
@@ -6,12 +6,12 @@ import (
"io"
"time"
- "tildegit.org/tjp/gus"
+ sr "tildegit.org/tjp/sliderule"
)
-func LogRequests(logger Logger) gus.Middleware {
- return func(inner gus.Handler) gus.Handler {
- return gus.HandlerFunc(func(ctx context.Context, request *gus.Request) *gus.Response {
+func LogRequests(logger Logger) sr.Middleware {
+ return func(inner sr.Handler) sr.Handler {
+ return sr.HandlerFunc(func(ctx context.Context, request *sr.Request) *sr.Response {
response := inner.Handle(ctx, request)
if response != nil {
response.Body = loggingBody(logger, request, response)
@@ -23,8 +23,8 @@ func LogRequests(logger Logger) gus.Middleware {
}
type loggedResponseBody struct {
- request *gus.Request
- response *gus.Response
+ request *sr.Request
+ response *sr.Response
body io.Reader
start time.Time
@@ -81,7 +81,7 @@ func (lwtr loggedWriteToResponseBody) WriteTo(dst io.Writer) (int64, error) {
return n, err
}
-func loggingBody(logger Logger, request *gus.Request, response *gus.Response) io.Reader {
+func loggingBody(logger Logger, request *sr.Request, response *sr.Response) io.Reader {
body := &loggedResponseBody{
request: request,
response: response,
diff --git a/logging/middleware_test.go b/logging/middleware_test.go
index 76406ef..390148e 100644
--- a/logging/middleware_test.go
+++ b/logging/middleware_test.go
@@ -8,17 +8,17 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/logging"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/logging"
)
func TestLogRequests(t *testing.T) {
logger := logRecorder{}
- handler := logging.LogRequests(&logger)(gus.HandlerFunc(func(_ context.Context, _ *gus.Request) *gus.Response {
- return &gus.Response{}
+ handler := logging.LogRequests(&logger)(sr.HandlerFunc(func(_ context.Context, _ *sr.Request) *sr.Response {
+ return &sr.Response{}
}))
- response := handler.Handle(context.Background(), &gus.Request{})
+ response := handler.Handle(context.Background(), &sr.Request{})
_, err := io.ReadAll(response.Body)
assert.Nil(t, err)
diff --git a/request.go b/request.go
index 1e0f3e7..dce8acb 100644
--- a/request.go
+++ b/request.go
@@ -1,4 +1,4 @@
-package gus
+package sliderule
import (
"crypto/tls"
@@ -20,6 +20,12 @@ type Request struct {
// It is unused on the client end.
Server Server
+ // Meta is a place for opaque data.
+ //
+ // Look for helper methods in protocol packages to use it appropriately
+ // for the protocol.
+ Meta any
+
// RemoteAddr is the address of the other side of the connection.
//
// This will be the server address for clients, or the connecting
diff --git a/request_test.go b/request_test.go
index 0da744f..29d0071 100644
--- a/request_test.go
+++ b/request_test.go
@@ -1,10 +1,10 @@
-package gus_test
+package sliderule_test
import (
"net/url"
"testing"
- "tildegit.org/tjp/gus"
+ sr "tildegit.org/tjp/sliderule"
)
func TestUnescapedQuery(t *testing.T) {
@@ -15,7 +15,7 @@ func TestUnescapedQuery(t *testing.T) {
for _, test := range table {
t.Run(test, func(t *testing.T) {
u, _ := url.Parse("gemini://domain.com/path?" + url.QueryEscape(test))
- result := gus.Request{URL: u}.UnescapedQuery()
+ result := sr.Request{URL: u}.UnescapedQuery()
if result != test {
t.Errorf("expected %q, got %q", test, result)
}
diff --git a/response.go b/response.go
index 369c5d1..249e08f 100644
--- a/response.go
+++ b/response.go
@@ -1,4 +1,4 @@
-package gus
+package sliderule
import "io"
diff --git a/router.go b/router.go
index 71fd086..6d0252f 100644
--- a/router.go
+++ b/router.go
@@ -1,10 +1,10 @@
-package gus
+package sliderule
import (
"context"
"strings"
- "tildegit.org/tjp/gus/internal"
+ "tildegit.org/tjp/sliderule/internal"
)
// Router stores a mapping of request path patterns to handlers.
diff --git a/router_test.go b/router_test.go
index bfc48bd..5430de7 100644
--- a/router_test.go
+++ b/router_test.go
@@ -1,4 +1,4 @@
-package gus_test
+package sliderule_test
import (
"bytes"
@@ -9,24 +9,24 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/gemini"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/gemini"
)
-var h1 = gus.HandlerFunc(func(_ context.Context, _ *gus.Request) *gus.Response {
+var h1 = sr.HandlerFunc(func(_ context.Context, _ *sr.Request) *sr.Response {
return gemini.Success("", &bytes.Buffer{})
})
-func mw1(h gus.Handler) gus.Handler {
- return gus.HandlerFunc(func(ctx context.Context, req *gus.Request) *gus.Response {
+func mw1(h sr.Handler) sr.Handler {
+ return sr.HandlerFunc(func(ctx context.Context, req *sr.Request) *sr.Response {
resp := h.Handle(ctx, req)
resp.Body = io.MultiReader(resp.Body, bytes.NewBufferString("\nmiddleware 1"))
return resp
})
}
-func mw2(h gus.Handler) gus.Handler {
- return gus.HandlerFunc(func(ctx context.Context, req *gus.Request) *gus.Response {
+func mw2(h sr.Handler) sr.Handler {
+ return sr.HandlerFunc(func(ctx context.Context, req *sr.Request) *sr.Response {
resp := h.Handle(ctx, req)
resp.Body = io.MultiReader(resp.Body, bytes.NewBufferString("\nmiddleware 2"))
return resp
@@ -34,7 +34,7 @@ func mw2(h gus.Handler) gus.Handler {
}
func TestRouterUse(t *testing.T) {
- r := &gus.Router{}
+ r := &sr.Router{}
r.Use(mw1)
r.Use(mw2)
r.Route("/", h1)
@@ -52,10 +52,10 @@ func TestRouterUse(t *testing.T) {
}
func TestRouterMount(t *testing.T) {
- outer := &gus.Router{}
+ outer := &sr.Router{}
outer.Use(mw2)
- inner := &gus.Router{}
+ inner := &sr.Router{}
inner.Use(mw1)
inner.Route("/bar", h1)
diff --git a/server.go b/server.go
index 686e92e..1562f56 100644
--- a/server.go
+++ b/server.go
@@ -1,4 +1,4 @@
-package gus
+package sliderule
// Server is a type which can serve a protocol.
type Server interface {
diff --git a/spartan/client.go b/spartan/client.go
index 154b18a..e571c14 100644
--- a/spartan/client.go
+++ b/spartan/client.go
@@ -7,7 +7,7 @@ import (
"net"
"strconv"
- "tildegit.org/tjp/gus"
+ sr "tildegit.org/tjp/sliderule"
)
// Client is used for sending spartan requests and receiving responses.
@@ -18,7 +18,7 @@ import (
type Client struct{}
// RoundTrip sends a single spartan request and returns its response.
-func (c Client) RoundTrip(request *gus.Request, body io.Reader) (*gus.Response, error) {
+func (c Client) RoundTrip(request *sr.Request, body io.Reader) (*sr.Response, error) {
if request.Scheme != "spartan" && request.Scheme != "" {
return nil, errors.New("non-spartan protocols not supported")
}
diff --git a/spartan/request.go b/spartan/request.go
index ca1159b..a9b2815 100644
--- a/spartan/request.go
+++ b/spartan/request.go
@@ -8,7 +8,7 @@ import (
"strconv"
"strings"
- "tildegit.org/tjp/gus"
+ sr "tildegit.org/tjp/sliderule"
)
var (
@@ -22,7 +22,7 @@ var (
// ParseRequest parses a single spartan request and the indicated content-length from a reader.
//
// If ther reader artument is a *bufio.Reader, it will only read a single line from it.
-func ParseRequest(rdr io.Reader) (*gus.Request, int, error) {
+func ParseRequest(rdr io.Reader) (*sr.Request, int, error) {
bufrdr, ok := rdr.(*bufio.Reader)
if !ok {
bufrdr = bufio.NewReader(rdr)
@@ -51,7 +51,7 @@ func ParseRequest(rdr io.Reader) (*gus.Request, int, error) {
return nil, 0, err
}
- return &gus.Request{
+ return &sr.Request{
URL: &url.URL{
Scheme: "spartan",
Host: host,
@@ -60,3 +60,23 @@ func ParseRequest(rdr io.Reader) (*gus.Request, int, error) {
},
}, contentlen, nil
}
+
+// GetRequestContentLength reads the remaining un-read number of bytes in a request body.
+//
+// It will immediately return 0 if there is no request body.
+func GetRequestContentLength(request *sr.Request) int {
+ if lr, ok := request.Meta.(*io.LimitedReader); ok {
+ return int(lr.N)
+ }
+ return 0
+}
+
+// GetRequestBody returns a reader of the spartan request body.
+//
+// It will return nil if the request has no body.
+func GetRequestBody(request *sr.Request) io.Reader {
+ if rdr, ok := request.Meta.(io.Reader); ok {
+ return rdr
+ }
+ return nil
+}
diff --git a/spartan/request_test.go b/spartan/request_test.go
index bffecef..89326f1 100644
--- a/spartan/request_test.go
+++ b/spartan/request_test.go
@@ -7,7 +7,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "tildegit.org/tjp/gus/spartan"
+ "tildegit.org/tjp/sliderule/spartan"
)
func TestParseRequest(t *testing.T) {
diff --git a/spartan/response.go b/spartan/response.go
index bd906e0..aeddd68 100644
--- a/spartan/response.go
+++ b/spartan/response.go
@@ -8,20 +8,20 @@ import (
"strconv"
"sync"
- "tildegit.org/tjp/gus"
+ sr "tildegit.org/tjp/sliderule"
)
// The spartan response types.
const (
- StatusSuccess gus.Status = 2
- StatusRedirect gus.Status = 3
- StatusClientError gus.Status = 4
- StatusServerError gus.Status = 5
+ StatusSuccess sr.Status = 2
+ StatusRedirect sr.Status = 3
+ StatusClientError sr.Status = 4
+ StatusServerError sr.Status = 5
)
// Success builds a successful spartan response.
-func Success(mediatype string, body io.Reader) *gus.Response {
- return &gus.Response{
+func Success(mediatype string, body io.Reader) *sr.Response {
+ return &sr.Response{
Status: StatusSuccess,
Meta: mediatype,
Body: body,
@@ -29,24 +29,24 @@ func Success(mediatype string, body io.Reader) *gus.Response {
}
// Redirect builds a spartan redirect response.
-func Redirect(url string) *gus.Response {
- return &gus.Response{
+func Redirect(url string) *sr.Response {
+ return &sr.Response{
Status: StatusRedirect,
Meta: url,
}
}
// ClientError builds a "client error" spartan response.
-func ClientError(err error) *gus.Response {
- return &gus.Response{
+func ClientError(err error) *sr.Response {
+ return &sr.Response{
Status: StatusClientError,
Meta: err.Error(),
}
}
// ServerError builds a "server error" spartan response.
-func ServerError(err error) *gus.Response {
- return &gus.Response{
+func ServerError(err error) *sr.Response {
+ return &sr.Response{
Status: StatusServerError,
Meta: err.Error(),
}
@@ -58,7 +58,7 @@ var InvalidResponseHeaderLine = errors.New("Invalid response header line.")
// InvalidResponseLineEnding indicates that a spartan response header didn't end with "\r\n".
var InvalidResponseLineEnding = errors.New("Invalid response line ending.")
-func ParseResponse(rdr io.Reader) (*gus.Response, error) {
+func ParseResponse(rdr io.Reader) (*sr.Response, error) {
bufrdr := bufio.NewReader(rdr)
hdrLine, err := bufrdr.ReadString('\n')
@@ -74,15 +74,15 @@ func ParseResponse(rdr io.Reader) (*gus.Response, error) {
return nil, InvalidResponseHeaderLine
}
- return &gus.Response{
- Status: gus.Status(status),
+ return &sr.Response{
+ Status: sr.Status(status),
Meta: hdrLine[2 : len(hdrLine)-2],
Body: bufrdr,
}, nil
}
// NewResponseReader builds a reader for a response.
-func NewResponseReader(response *gus.Response) gus.ResponseReader {
+func NewResponseReader(response *sr.Response) sr.ResponseReader {
return &responseReader{
Response: response,
once: &sync.Once{},
@@ -90,7 +90,7 @@ func NewResponseReader(response *gus.Response) gus.ResponseReader {
}
type responseReader struct {
- *gus.Response
+ *sr.Response
reader io.Reader
once *sync.Once
}
diff --git a/spartan/serve.go b/spartan/serve.go
index 677d76c..61199b1 100644
--- a/spartan/serve.go
+++ b/spartan/serve.go
@@ -9,27 +9,14 @@ import (
"net"
"strings"
- "tildegit.org/tjp/gus"
- "tildegit.org/tjp/gus/internal"
- "tildegit.org/tjp/gus/logging"
+ sr "tildegit.org/tjp/sliderule"
+ "tildegit.org/tjp/sliderule/internal"
+ "tildegit.org/tjp/sliderule/logging"
)
-type spartanRequestBodyKey struct{}
-type spartanRequestBodyLenKey struct{}
-
-// SpartanRequestBody is the key set in a handler's context for spartan request bodies.
-//
-// The corresponding value is a *bufio.Reader from which the request body can be read.
-var SpartanRequestBody = spartanRequestBodyKey{}
-
-// SpartanRequestBodyLen is the key set in a handler's context for the content-length of the request.
-//
-// The corresponding value is an int.
-var SpartanRequestBodyLen = spartanRequestBodyLenKey{}
-
type spartanServer struct {
internal.Server
- handler gus.Handler
+ handler sr.Handler
}
func (ss spartanServer) Protocol() string { return "SPARTAN" }
@@ -40,9 +27,9 @@ func NewServer(
hostname string,
network string,
address string,
- handler gus.Handler,
+ handler sr.Handler,
errLog logging.Logger,
-) (gus.Server, error) {
+) (sr.Server, error) {
ss := &spartanServer{handler: handler}
if strings.IndexByte(hostname, ':') < 0 {
@@ -61,7 +48,7 @@ func NewServer(
func (ss *spartanServer) handleConn(conn net.Conn) {
buf := bufio.NewReader(conn)
- var response *gus.Response
+ var response *sr.Response
request, clen, err := ParseRequest(buf)
if err != nil {
response = ClientError(err)
@@ -69,12 +56,11 @@ func (ss *spartanServer) handleConn(conn net.Conn) {
request.Server = ss
request.RemoteAddr = conn.RemoteAddr()
- var body *bufio.Reader = nil
+ var body io.Reader = nil
if clen > 0 {
- body = bufio.NewReader(io.LimitReader(buf, int64(clen)))
+ body = io.LimitReader(buf, int64(clen))
}
- ctx := context.WithValue(ss.Ctx, SpartanRequestBody, body)
- ctx = context.WithValue(ctx, SpartanRequestBodyLen, clen)
+ request.Meta = body
defer func() {
if r := recover(); r != nil {
@@ -84,7 +70,7 @@ func (ss *spartanServer) handleConn(conn net.Conn) {
_, _ = io.Copy(conn, rdr)
}
}()
- response = ss.handler.Handle(ctx, request)
+ response = ss.handler.Handle(ss.Ctx, request)
if response == nil {
response = ClientError(errors.New("Resource does not exist."))
}