diff options
Diffstat (limited to 'gemini')
-rw-r--r-- | gemini/client.go | 4 | ||||
-rw-r--r-- | gemini/gemtext/fuzz_test.go | 2 | ||||
-rw-r--r-- | gemini/gemtext/htmlconv/convert.go | 4 | ||||
-rw-r--r-- | gemini/gemtext/htmlconv/convert_test.go | 4 | ||||
-rw-r--r-- | gemini/gemtext/internal/templates.go | 2 | ||||
-rw-r--r-- | gemini/gemtext/mdconv/convert.go | 4 | ||||
-rw-r--r-- | gemini/gemtext/mdconv/convert_test.go | 4 | ||||
-rw-r--r-- | gemini/gemtext/parse_line_test.go | 2 | ||||
-rw-r--r-- | gemini/gemtext/parse_test.go | 2 | ||||
-rw-r--r-- | gemini/request.go | 20 | ||||
-rw-r--r-- | gemini/request_test.go | 2 | ||||
-rw-r--r-- | gemini/response.go | 100 | ||||
-rw-r--r-- | gemini/response_test.go | 20 | ||||
-rw-r--r-- | gemini/roundtrip_test.go | 12 | ||||
-rw-r--r-- | gemini/serve.go | 32 |
15 files changed, 109 insertions, 105 deletions
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) } |