lots more documentation comments
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
197d8e4cb0
commit
e183f9cd23
|
@ -23,7 +23,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 := gemini.Fallthrough(
|
||||
handler := gemini.FallthroughHandler(
|
||||
// first see if they're fetching a directory and we have <dir>/index.gmi
|
||||
fs.DirectoryDefault(fileSystem, "index.gmi"),
|
||||
// next (still if they requested a directory) build a directory listing response
|
||||
|
|
|
@ -28,6 +28,9 @@ func NewClient(tlsConf *tls.Config) Client {
|
|||
//
|
||||
// It also populates the TLSState and RemoteAddr fields on the request - the only field
|
||||
// it needs populated beforehand is the URL.
|
||||
//
|
||||
// This method will not automatically follow redirects or cache permanent failures or
|
||||
// redirects.
|
||||
func (client Client) RoundTrip(request *Request) (*Response, error) {
|
||||
if request.Scheme != "gemini" && request.Scheme != "" {
|
||||
return nil, errors.New("non-gemini protocols not supported")
|
||||
|
@ -57,8 +60,8 @@ func (client Client) RoundTrip(request *Request) (*Response, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// read and store the request body in full or we may miss doing so before the
|
||||
// connection gets closed.
|
||||
// read and store the request body in full or we may miss doing so before
|
||||
// closing the connection
|
||||
bodybuf, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -6,7 +6,7 @@ import "context"
|
|||
//
|
||||
// A Handler MUST NOT return a nil response. Errors should be returned in the form
|
||||
// of error responses (4x, 5x, 6x response status). If the Handler should not be
|
||||
// responsible for the requested resource it can return a "51 Not Found" response.
|
||||
// responsible for the requested resource it can return a 51 response.
|
||||
type Handler func(context.Context, *Request) *Response
|
||||
|
||||
// Middleware is a handle decorator.
|
||||
|
@ -15,7 +15,11 @@ type Handler func(context.Context, *Request) *Response
|
|||
// transform the request or response in some way.
|
||||
type Middleware func(Handler) Handler
|
||||
|
||||
func Fallthrough(handlers ...Handler) Handler {
|
||||
// FallthroughHandler builds a handler which tries multiple child handlers.
|
||||
//
|
||||
// The returned handler will invoke each of the passed child handlers in order,
|
||||
// stopping when it receives a response with status other than 51.
|
||||
func FallthroughHandler(handlers ...Handler) Handler {
|
||||
return func(ctx context.Context, req *Request) *Response {
|
||||
for _, handler := range handlers {
|
||||
response := handler(ctx, req)
|
||||
|
@ -27,3 +31,24 @@ func Fallthrough(handlers ...Handler) Handler {
|
|||
return NotFound("Resource does not exist.")
|
||||
}
|
||||
}
|
||||
|
||||
// Filter wraps a handler with a predicate which determines whether to run the handler.
|
||||
//
|
||||
// When the predicate function returns false, the Filter returns the provided failure
|
||||
// response. The failure argument may be nil, in which case a "51 Resource does not exist."
|
||||
// response will be used.
|
||||
func Filter(
|
||||
predicate func(context.Context, *Request) bool,
|
||||
handler Handler,
|
||||
failure *Response,
|
||||
) Handler {
|
||||
if failure == nil {
|
||||
failure = NotFound("Resource does not exist.")
|
||||
}
|
||||
return func(ctx context.Context, req *Request) *Response {
|
||||
if !predicate(ctx, req) {
|
||||
return failure
|
||||
}
|
||||
return handler(ctx, req)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,10 +14,26 @@ var InvalidRequestLineEnding = errors.New("invalid request line ending")
|
|||
|
||||
// Request represents a request over the gemini protocol.
|
||||
type Request struct {
|
||||
// URL is the specific URL being fetched by the request.
|
||||
*url.URL
|
||||
|
||||
// Server is the server which received the request.
|
||||
//
|
||||
// This is only populated in gemini servers.
|
||||
// It is unused on the client end.
|
||||
Server *Server
|
||||
|
||||
// RemoteAddr is the address of the other side of the connection.
|
||||
//
|
||||
// This will be the server address for clients, or the connecting
|
||||
// client's address in servers.
|
||||
//
|
||||
// Be aware though that proxies (and reverse proxies) can confuse this.
|
||||
RemoteAddr net.Addr
|
||||
|
||||
// TLSState contains information about the TLS encryption over the connection.
|
||||
//
|
||||
// This includes peer certificates and version information.
|
||||
TLSState *tls.ConnectionState
|
||||
}
|
||||
|
||||
|
|
|
@ -114,6 +114,8 @@ type Response struct {
|
|||
Meta string
|
||||
|
||||
// Body is the response body, if any.
|
||||
//
|
||||
// It is not guaranteed to be readable more than once.
|
||||
Body io.Reader
|
||||
|
||||
reader io.Reader
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"sync"
|
||||
)
|
||||
|
||||
// Server listens on a network and serves the gemini protocol.
|
||||
type Server struct {
|
||||
ctx context.Context
|
||||
network string
|
||||
|
@ -18,6 +19,7 @@ type Server struct {
|
|||
handler Handler
|
||||
}
|
||||
|
||||
// NewServer builds a server.
|
||||
func NewServer(
|
||||
ctx context.Context,
|
||||
tlsConfig *tls.Config,
|
||||
|
@ -46,6 +48,10 @@ func NewServer(
|
|||
//
|
||||
// This function will allocate resources which are not cleaned up until
|
||||
// Close() is called.
|
||||
//
|
||||
// It will respect cancellation of the context the server was created with,
|
||||
// but be aware that Close() must still be called in that case to avoid
|
||||
// dangling goroutines.
|
||||
func (s *Server) Serve() error {
|
||||
s.wg.Add(1)
|
||||
defer s.wg.Done()
|
||||
|
|
|
@ -2,6 +2,9 @@ package gemini
|
|||
|
||||
import "crypto/tls"
|
||||
|
||||
// FileTLS builds a TLS configuration from paths to a certificate and key file.
|
||||
//
|
||||
// It sets parameters on the configuration to make it suitable for use with gemini.
|
||||
func FileTLS(certfile string, keyfile string) (*tls.Config, error) {
|
||||
cert, err := tls.LoadX509KeyPair(certfile, keyfile)
|
||||
if err != nil {
|
||||
|
|
Reference in New Issue