Documentation ¶
Overview ¶
Package gemproto provides client and server implementations for the Gemini protocol.
Index ¶
- Constants
- Variables
- func Input(prompt string) func(Handler) Handler
- func NotFound(w ResponseWriter, r *Request)
- func Redirect(w ResponseWriter, r *Request, url string, code int)
- type Client
- type Dir
- type FileServerFlags
- type GetCertificateFunc
- type Handler
- type HandlerFunc
- type Host
- type HostsFile
- type Logger
- type RedirectError
- type Request
- type Response
- type ResponseWriter
- type ServeMux
- func (mux *ServeMux) Handle(pattern string, handler Handler)
- func (mux *ServeMux) HandleFunc(pattern string, handler HandlerFunc)
- func (mux *ServeMux) Handler(r *Request) (handler Handler, pattern string)
- func (mux *ServeMux) Mount(pattern string, handler Handler)
- func (mux *ServeMux) NotFound(h HandlerFunc)
- func (mux *ServeMux) Route(pattern string, fn func(*ServeMux))
- func (mux *ServeMux) ServeGemini(w ResponseWriter, r *Request)
- type Server
Constants ¶
const ( StatusInput = 10 StatusSensitiveInput = 11 StatusOK = 20 StatusTemporaryRedirect = 30 StatusPermanentRedirect = 31 StatusTemporaryFailure = 40 StatusCGIError = 42 StatusProxyError = 43 StatusSlowDown = 44 StatusPermanentFailure = 50 StatusNotFound = 51 StatusGone = 52 StatusProxyRequestRefused = 53 StatusBadRequest = 59 StatusClientCertificateRequired = 60 StatusClientCertificateNotAuthorized = 61 StatusClientCertificateNotValid = 62 )
Gemini status codes as described in the specification. See: https://geminiprotocol.net/docs/specification.gmi
Variables ¶
var ErrCertificateNotTrusted = errors.New("gemproto: certificate not trusted")
var ErrInvalidResponse = errors.New("gemproto: invalid response")
ErrInvalidResponse is returned by Client if it received an invalid response.
var ErrServerClosed = errors.New("gemproto: server closed")
ErrServerClosed is returned by Listen when the server has been closed.
Functions ¶
Types ¶
type Client ¶
type Client struct { // ConnectTimeout sets the idle timeout. ConnectTimeout time.Duration // ReadTimeout sets the read timeout. ReadTimeout time.Duration // WriteTimeout sets the write timeout. WriteTimeout time.Duration // HostsFile is optional and specifies to verify hosts. HostsFile *HostsFile // GetCertificate is optional and maps hostnames to client certificates. GetCertificate GetCertificateFunc }
Client implements the client side of the Gemini protocol.
The client must close the response body when done with it:
client := gemproto.Client{} resp, err := client.Get("gemini://gemini.circumlunar.space") if err != nil { // handle error } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) // ...
Client can optionally provide a certificate to authenticate itself to hosts:
cert, err := gemcert.LoadX509KeyPair("client.crt", "client.key") if err != nil { // handle error } client := gemproto.Client{ GetCertificate: gemproto.SingleClientCertificate(cert), } // ...
Client can optionally verify and record host certificates using the TOFU mechanism by creating a HostsFile:
hostsfile, f, err := gemproto.OpenHostsFile("./hostsfile") if err != nil { // handle error } defer f.Close() client := gemproto.Client{ HostsFile: hostsfile, } // ...
type FileServerFlags ¶
type FileServerFlags int
FileServerFlags enumerates all FileServer capability flags.
const ( // ListDirs enables directory listing. ListDirs FileServerFlags = 1 << iota // ShowHiddenFiles enables dot-files to be listed. ShowHiddenFiles // UseMetaFile enables the .meta file to be scanned. UseMetaFile )
type GetCertificateFunc ¶
type GetCertificateFunc func(hostname string) (tls.Certificate, bool)
GetCertificateFunc is a function that maps a hostname to a certificate.
func SingleClientCertificate ¶
func SingleClientCertificate(cert tls.Certificate) GetCertificateFunc
SingleClientCertificate returns the same certificate regardless of hostname.
type Handler ¶
type Handler interface {
ServeGemini(ResponseWriter, *Request)
}
Handler responds to a Gemini request.
func FileServer ¶
func FileServer(root fs.FS, flags FileServerFlags) Handler
FileServer returns a handler that serves Gemini requests with the contents of the file system rooted at root.
As a special case, the returned file server redirects any request ending in "/index.gmi" to the same path, without the final "index.gmi".
To use the operating system's file system implementation, use gemproto.Dir:
serveMux.Handle("/", gemproto.FileServer(gemproto.Dir("/tmp", 0)))
Flags ¶
FileServer accepts flags to enable certain capabilities.
ListDirs enables listing directory contents if there is no index.gmi in the directory.
ShowHiddenFiles enables hidden files and directories to be accessed.
UseMetaFile enables parsing the .meta file to customize the metadata of any files accessed in the same directory as the .meta file.
The .meta file has the following format:
- Empty lines and lines starting with a '#' are ignored.
- All other lines must have the form <pattern>:<metadata>, where <pattern> is a file pattern and metadata is either a mimetype or a valid Gemini response line. Mimetypes starting with ';' are appended. Response lines have the form <2digitcode><space><metadata>.
func NotFoundHandler ¶
func NotFoundHandler() Handler
NotFoundHandler returns a Handler that responds with 51 Not Found.
func RedirectHandler ¶
RedirectHandler returns a Handler that redirects to the given URL.
func StripPrefix ¶
StripPrefix returns a handler that serves Gemini requests by removing the given prefix from the request URL's Path (and RawPath if set) and invoking the handler h. StripPrefix handles a request for a path that doesn't begin with prefix by replying with 51 Not Found. The prefix must match exactly: if the prefix in the request contains escaped characters the reply is also 51 Not Found.
type HandlerFunc ¶
type HandlerFunc func(ResponseWriter, *Request)
HandlerFunc adapts a function to the Handler interface.
func (HandlerFunc) ServeGemini ¶
func (f HandlerFunc) ServeGemini(w ResponseWriter, r *Request)
ServeGemini implements Handler.
type Host ¶
type Host struct { // Addr is the domain:port of the remote host. Addr string // Algorithm is the algorithm used to compute the fingerprint. Algorithm string // Fingerprint is a hash of the host's certificate. Fingerprint string // NotAfter is the expiry time of the certificate. NotAfter time.Time }
Host is an entry in HostsFile.
type HostsFile ¶
type HostsFile struct {
// contains filtered or unexported fields
}
HostsFile implements the Trust-On-First-Use (TOFU) mechanism by maintaining a set of known hosts in an append-only hostsfile.
HostsFile is intended to be used with Client by setting the TrustCertificate field. TrustCertificate applies the TOFU algorithm and updates the hostsfile as needed.
The hostsfile is append-only but HostsFile only stores the latest entries in memory. Older entries are retained for auditing purposes.
HostsFile is safe to use concurrently.
File Format ¶
Each line in the hostsfile is an entry. An entry consists of four fields separated by spaces and delimited by a newline:
address<SPACE>algorithm<SPACE>fingerprint<SPACE>expiry<LF>
- address is the domain:port of the remote host.
- port is the port number of the remote host.
- algorithm is the hashing algorithm used to compute the fingerprint.
- fingerprint is the base64 encoding of the hash of the certificate's Subject Public Key Info (SPKI) section.
- expiry is the expiration date of the certificate.
Later entries overwrite older entries. Lines that do not conform to this format are ignored.
func NewHostsFile ¶
NewHostsFile returns a new HostsFile.
New entries are written to w and flushed if w implements `Flush() error`.
func OpenHostsFile ¶
OpenHostsFile is a shorthand for opening and reading a hostsfile. The file is opened in append mode and is created if it does not exist yet. The callee is responsible for calling os/File.Close to close the file.
func (*HostsFile) ReadFrom ¶
ReadFrom parses a hostsfile and stores the entries in memory. Later entries overwrite earlier ones.
func (*HostsFile) SetHost ¶
SetHost sets the host entry and writes it to the Writer set by NewHostsFile.
func (*HostsFile) TrustCertificate ¶
func (hf *HostsFile) TrustCertificate(cert *x509.Certificate, addr string) error
TrustCertificate applies the Trust On First Use algorithm to the given certificate and remote host address.
type RedirectError ¶
type RedirectError struct { // LastURL is the last URL that the client was redirected from. LastURL string // NextURL is the next URL that the client was redirected to. NextURL string }
RedirectError is returned by Client.Do if the maximum number of redirects has been exceeded.
func (RedirectError) Error ¶
func (err RedirectError) Error() string
Error implements the error interface.
type Request ¶
type Request struct { // URL is the url requested by the client. URL *url.URL // RequestURI is set by Server and holds the raw URL requested by the client. RequestURI string // RemoteAddr is set by Server and holds the remote address of the client. RemoteAddr string // Host is the Server Name Indication (SNI) passed by the client. // It is automatically set by Server when it receives a request. // It must be set manually to use SNI in Client requests, // otherwise it defaults to URL.Host. Host string // TLS holds the basic TLS connection details. TLS *tls.ConnectionState // contains filtered or unexported fields }
Request represents a request that has been received by the server.
func NewRequest ¶
NewRequest creates a new request with the default context.
func NewRequestWithContext ¶
NewRequestWithContext creates a new request with a context.
type Response ¶
type Response struct { // URL is the absolute URL that sent the response. // It can be different from the request URL if the request was redirected. URL *url.URL // StatusCode is the response code. StatusCode int // Meta is the response metadata. // It is interpreted differently depending on the status code. Meta string // Body is the request body. // It is never nil and must be Closed. Body io.ReadCloser // TLS holds the basic TLS connection details. TLS *tls.ConnectionState }
Response is the response received from a server.
type ResponseWriter ¶
ResponseWriter is used to construct the response.
WriteHeader sets the response header. It is not actually written until the first call to Write. The header will not be written if statusCode is set to a value lower than 10. This can be used to create CGI handlers that write the header manually.
type ServeMux ¶
type ServeMux struct {
// contains filtered or unexported fields
}
ServeMux is an Gemini request multiplexer. It matches the URL of each incoming request against a list of registered patterns and calls the handler for the pattern that most closely matches the URL.
It functions just like http.ServeMux.
func (*ServeMux) Handle ¶
Handle registers the handler for the given pattern. If a handler already exists for pattern, Handle panics.
func (*ServeMux) HandleFunc ¶
func (mux *ServeMux) HandleFunc(pattern string, handler HandlerFunc)
HandleFunc registers the handler function for the given pattern.
func (*ServeMux) Handler ¶
Handler returns the handler to use for the given request, consulting r.Host and r.URL.Path. It always returns a non-nil handler. If the path is not in its canonical form, the handler will be an internally-generated handler that redirects to the canonical path. If the host contains a port, it is ignored when matching handlers.
Handler also returns the registered pattern that matches the request or, in the case of internally-generated redirects, the pattern that will match after following the redirect.
If there is no registered handler that applies to the request, Handler returns the handler set by NotFound.
func (*ServeMux) Mount ¶
Mount attaches a handler as a subrouter along a routing path. The prefixed pattern is stripped from the route.
func (*ServeMux) NotFound ¶
func (mux *ServeMux) NotFound(h HandlerFunc)
NotFound sets the handler to use when a requested resource is not found. It defaults to the NotFound function.
func (*ServeMux) ServeGemini ¶
func (mux *ServeMux) ServeGemini(w ResponseWriter, r *Request)
ServeGemini implements Handler.
type Server ¶
type Server struct { // Addr is the address to listen on. // Defaults to :1965 if empty. Addr string // Handler is invoked to handle all requests. Handler Handler // Logger logs various diagnostics if it is not nil. Logger Logger // TLSConfig configures the TLS. TLSConfig *tls.Config // ReadTimeout sets the maximum duration for reading an incoming request. ReadTimeout time.Duration // WriteTimeout sets the maximum duration before // timing out on writing an outgoing response. WriteTimeout time.Duration // Insecure disables TLS. // It should only be set if the server is behind a reverse proxy. // Insecure servers do not support Server Name Indication (SNI). Insecure bool }
Server defines parameters for running a Gemini server.
The zero value for Server is not a valid configuration. The TLSConfig must be set and must contain at least one certificate or non-nil GetCertificate.
func (*Server) ListenAndServe ¶
ListenAndServe starts the server loop. The server loop ends when the passed context is cancelled.
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
cmd
|
|
Package gemcert provides utilities for creating certificates.
|
Package gemcert provides utilities for creating certificates. |
Package gemtest contains utilities for writing tests.
|
Package gemtest contains utilities for writing tests. |
Package gemtext contains utilities for handling gemtext files.
|
Package gemtext contains utilities for handling gemtext files. |
internal
|
|