go-gemini/gmi.go

99 lines
2.8 KiB
Go
Raw Normal View History

2020-09-28 00:20:59 +00:00
package gmi
2020-09-25 23:09:49 +00:00
2020-09-26 20:52:14 +00:00
import (
"crypto/tls"
2020-09-26 20:52:14 +00:00
"crypto/x509"
2020-10-14 00:10:04 +00:00
"errors"
2020-09-26 20:52:14 +00:00
"sync"
"time"
2020-09-26 20:52:14 +00:00
)
2020-09-25 23:09:49 +00:00
// Status codes.
const (
2020-09-28 01:13:42 +00:00
StatusInput = 10
StatusSensitiveInput = 11
StatusSuccess = 20
StatusRedirect = 30
StatusRedirectPermanent = 31
StatusTemporaryFailure = 40
StatusServerUnavailable = 41
StatusCGIError = 42
StatusProxyError = 43
StatusSlowDown = 44
StatusPermanentFailure = 50
StatusNotFound = 51
StatusGone = 52
StatusProxyRequestRefused = 53
StatusBadRequest = 59
StatusCertificateRequired = 60
StatusCertificateNotAuthorized = 61
StatusCertificateNotValid = 62
2020-09-25 23:09:49 +00:00
)
// Status code categories.
const (
2020-09-28 01:13:42 +00:00
StatusClassInput = 1
StatusClassSuccess = 2
StatusClassRedirect = 3
StatusClassTemporaryFailure = 4
StatusClassPermanentFailure = 5
StatusClassCertificateRequired = 6
2020-09-25 23:09:49 +00:00
)
2020-10-14 00:10:04 +00:00
// Errors.
var (
ErrInvalidURL = errors.New("gmi: invalid URL")
ErrInvalidResponse = errors.New("gmi: invalid response")
ErrCertificateUnknown = errors.New("gmi: unknown certificate")
ErrCertificateExpired = errors.New("gmi: certificate expired")
ErrCertificateNotTrusted = errors.New("gmi: certificate is not trusted")
ErrNotAFile = errors.New("gmi: not a file")
ErrBodyNotAllowed = errors.New("gmi: response status code does not allow for body")
)
2020-09-26 20:52:14 +00:00
// DefaultClient is the default client. It is used by Send.
//
// On the first request, DefaultClient will load the default list of known hosts.
2020-10-14 00:10:04 +00:00
var DefaultClient Client
2020-09-26 20:52:14 +00:00
2020-09-28 02:15:36 +00:00
var (
crlf = []byte("\r\n")
)
2020-09-26 20:52:14 +00:00
func init() {
2020-09-28 02:18:21 +00:00
DefaultClient.TrustCertificate = func(hostname string, cert *x509.Certificate, knownHosts *KnownHosts) error {
// Load the hosts only once. This is so that the hosts don't have to be loaded
// for those using their own clients.
setupDefaultClientOnce.Do(setupDefaultClient)
return knownHosts.Lookup(hostname, cert)
2020-09-26 20:52:14 +00:00
}
2020-10-12 20:34:52 +00:00
DefaultClient.GetCertificate = func(hostname string, store *CertificateStore) *tls.Certificate {
// If the certificate is in the store, return it
2020-10-12 03:48:18 +00:00
if cert, err := store.Lookup(hostname); err == nil {
return cert
}
// Otherwise, generate a certificate
duration := time.Hour
cert, err := NewCertificate(hostname, duration)
if err != nil {
return nil
}
// Store and return the certificate
2020-10-12 03:48:18 +00:00
store.Add(hostname, cert)
return &cert
}
2020-09-26 20:52:14 +00:00
}
var setupDefaultClientOnce sync.Once
func setupDefaultClient() {
DefaultClient.KnownHosts.LoadDefault()
2020-09-26 20:52:14 +00:00
}
// Send sends a Gemini request and returns a Gemini response.
//
// Send is a wrapper around DefaultClient.Send.
func Send(req *Request) (*Response, error) {
return DefaultClient.Send(req)
}