aboutsummaryrefslogtreecommitdiff
path: root/server.go
diff options
context:
space:
mode:
authorAdnan Maolood <[email protected]>2021-01-25 10:55:38 -0500
committerAdnan Maolood <[email protected]>2021-01-25 10:55:40 -0500
commit9e89b93bab846eb1d23ba618df86961ff0b5c2f4 (patch)
tree97f158ccfb0f8a2742f5440714fc3617a6a8da1a /server.go
parentGuarantee that (*Response).Body is not nil (diff)
downloadgo-gemini-9e89b93bab846eb1d23ba618df86961ff0b5c2f4.tar.xz
go-gemini-9e89b93bab846eb1d23ba618df86961ff0b5c2f4.zip
server: Allow handling any hostname with "*"
Allow registering a responder with the special pattern "*" to handle any hostname.
Diffstat (limited to 'server.go')
-rw-r--r--server.go35
1 files changed, 26 insertions, 9 deletions
diff --git a/server.go b/server.go
index b1f83af..523cb39 100644
--- a/server.go
+++ b/server.go
@@ -27,9 +27,9 @@ type Server struct {
// Certificates contains the certificates used by the server.
Certificates certificate.Dir
- // CreateCertificate, if not nil, will be called to create a new certificate
+ // GetCertificate, if not nil, will be called to retrieve a new certificate
// if the current one is expired or missing.
- CreateCertificate func(hostname string) (tls.Certificate, error)
+ GetCertificate func(hostname string) (tls.Certificate, error)
// ErrorLog specifies an optional logger for errors accepting connections
// and file system errors.
@@ -51,6 +51,7 @@ type responderKey struct {
// The pattern must be in the form of "hostname" or "scheme://hostname".
// If no scheme is specified, a scheme of "gemini://" is implied.
// Wildcard patterns are supported (e.g. "*.example.com").
+// To handle any hostname, use the wildcard pattern "*".
func (s *Server) Handle(pattern string, responder Responder) {
if pattern == "" {
panic("gemini: invalid pattern")
@@ -136,28 +137,40 @@ func (s *Server) Serve(l net.Listener) error {
}
}
+// getCertificate retrieves a certificate for the given client hello.
func (s *Server) getCertificate(h *tls.ClientHelloInfo) (*tls.Certificate, error) {
- cert, err := s.getCertificateFor(h.ServerName)
+ cert, err := s.lookupCertificate(h.ServerName, h.ServerName)
if err != nil {
// Try wildcard
wildcard := strings.SplitN(h.ServerName, ".", 2)
if len(wildcard) == 2 {
- cert, err = s.getCertificateFor("*." + wildcard[1])
+ // Use the wildcard pattern as the hostname.
+ hostname := "*." + wildcard[1]
+ cert, err = s.lookupCertificate(hostname, hostname)
+ }
+ // Try "*" wildcard
+ if err != nil {
+ // Use the server name as the hostname
+ // since "*" is not a valid hostname.
+ cert, err = s.lookupCertificate("*", h.ServerName)
}
}
return cert, err
}
-func (s *Server) getCertificateFor(hostname string) (*tls.Certificate, error) {
- if _, ok := s.hosts[hostname]; !ok {
+// lookupCertificate retrieves the certificate for the given hostname,
+// if and only if the provided pattern is registered.
+// If no certificate is found in the certificate store or the certificate
+// is expired, it calls GetCertificate to retrieve a new certificate.
+func (s *Server) lookupCertificate(pattern, hostname string) (*tls.Certificate, error) {
+ if _, ok := s.hosts[pattern]; !ok {
return nil, errors.New("hostname not registered")
}
- // Generate a new certificate if it is missing or expired
cert, ok := s.Certificates.Lookup(hostname)
if !ok || cert.Leaf != nil && cert.Leaf.NotAfter.Before(time.Now()) {
- if s.CreateCertificate != nil {
- cert, err := s.CreateCertificate(hostname)
+ if s.GetCertificate != nil {
+ cert, err := s.GetCertificate(hostname)
if err == nil {
if err := s.Certificates.Add(hostname, cert); err != nil {
s.logf("gemini: Failed to write new certificate for %s: %s", hostname, err)
@@ -167,6 +180,7 @@ func (s *Server) getCertificateFor(hostname string) (*tls.Certificate, error) {
}
return nil, errors.New("no certificate")
}
+
return &cert, nil
}
@@ -223,6 +237,9 @@ func (s *Server) responder(r *Request) Responder {
return h
}
}
+ if h, ok := s.responders[responderKey{r.URL.Scheme, "*"}]; ok {
+ return h
+ }
return nil
}