server: Allow handling any hostname with "*"
Allow registering a responder with the special pattern "*" to handle any hostname.
This commit is contained in:
parent
31de8d49b0
commit
9e89b93bab
35
server.go
35
server.go
@ -27,9 +27,9 @@ type Server struct {
|
|||||||
// Certificates contains the certificates used by the server.
|
// Certificates contains the certificates used by the server.
|
||||||
Certificates certificate.Dir
|
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.
|
// 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
|
// ErrorLog specifies an optional logger for errors accepting connections
|
||||||
// and file system errors.
|
// and file system errors.
|
||||||
@ -51,6 +51,7 @@ type responderKey struct {
|
|||||||
// The pattern must be in the form of "hostname" or "scheme://hostname".
|
// The pattern must be in the form of "hostname" or "scheme://hostname".
|
||||||
// If no scheme is specified, a scheme of "gemini://" is implied.
|
// If no scheme is specified, a scheme of "gemini://" is implied.
|
||||||
// Wildcard patterns are supported (e.g. "*.example.com").
|
// Wildcard patterns are supported (e.g. "*.example.com").
|
||||||
|
// To handle any hostname, use the wildcard pattern "*".
|
||||||
func (s *Server) Handle(pattern string, responder Responder) {
|
func (s *Server) Handle(pattern string, responder Responder) {
|
||||||
if pattern == "" {
|
if pattern == "" {
|
||||||
panic("gemini: invalid 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) {
|
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 {
|
if err != nil {
|
||||||
// Try wildcard
|
// Try wildcard
|
||||||
wildcard := strings.SplitN(h.ServerName, ".", 2)
|
wildcard := strings.SplitN(h.ServerName, ".", 2)
|
||||||
if len(wildcard) == 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
|
return cert, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getCertificateFor(hostname string) (*tls.Certificate, error) {
|
// lookupCertificate retrieves the certificate for the given hostname,
|
||||||
if _, ok := s.hosts[hostname]; !ok {
|
// 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")
|
return nil, errors.New("hostname not registered")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a new certificate if it is missing or expired
|
|
||||||
cert, ok := s.Certificates.Lookup(hostname)
|
cert, ok := s.Certificates.Lookup(hostname)
|
||||||
if !ok || cert.Leaf != nil && cert.Leaf.NotAfter.Before(time.Now()) {
|
if !ok || cert.Leaf != nil && cert.Leaf.NotAfter.Before(time.Now()) {
|
||||||
if s.CreateCertificate != nil {
|
if s.GetCertificate != nil {
|
||||||
cert, err := s.CreateCertificate(hostname)
|
cert, err := s.GetCertificate(hostname)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if err := s.Certificates.Add(hostname, cert); err != nil {
|
if err := s.Certificates.Add(hostname, cert); err != nil {
|
||||||
s.logf("gemini: Failed to write new certificate for %s: %s", hostname, err)
|
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 nil, errors.New("no certificate")
|
||||||
}
|
}
|
||||||
|
|
||||||
return &cert, nil
|
return &cert, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,6 +237,9 @@ func (s *Server) responder(r *Request) Responder {
|
|||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if h, ok := s.responders[responderKey{r.URL.Scheme, "*"}]; ok {
|
||||||
|
return h
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user