package main
import (
"bufio"
"crypto/tls"
"fmt"
"net"
"net/url"
"strings"
"time"
"unicode/utf8"
)
var reloadTime time.Time
func startServer() {
for {
ln, err := listenTLSServer(config.Listen)
if err != nil {
fmt.Println("Error starting server", err)
return
}
defer ln.Close()
go waitForCertReload(ln)
fmt.Println("Accepting new connections on", ln.Addr())
for {
conn, err := ln.Accept()
if err != nil {
fmt.Println("Error accepting connections", err)
break
}
go handleConnection(conn)
}
}
}
func waitForCertReload(ln net.Listener) {
fmt.Println("Will reload certs on", reloadTime)
<-time.After(time.Until(reloadTime))
fmt.Println("Certificates expired, reloading server")
ln.Close()
}
func listenTLSServer(addr string) (net.Listener, error) {
cfg := getTLSConfig()
addr = parseAddr(addr)
return tls.Listen("tcp", addr, cfg)
}
func handleConnection(c net.Conn) {
defer c.Close()
req, err := bufio.NewReader(c).ReadString('\r')
if err != nil {
return
}
rawURL := strings.TrimSpace(req)
if rawURL == "" {
sendError(c, BadRequest, "Empty URL")
return
} else if !utf8.ValidString(rawURL) {
sendError(c, BadRequest, "Non UTF-8 Request")
return
} else if len(rawURL) > MaxURLSize {
sendError(c, BadRequest, "URL Larger than 1024 bytes")
return
}
parsedURL, err := url.Parse(rawURL)
if err != nil {
sendError(c, BadRequest, "Bad URL")
}
if parsedURL.Scheme == "" {
parsedURL.Scheme = "gemini"
}
if parsedURL.Scheme != "gemini" {
sendError(c, ProxyRequestRefused, fmt.Sprintf("Unknown scheme '%s'", parsedURL.Scheme))
return
} else if parsedURL.Host == "" {
sendError(c, BadRequest, "Host not supplied")
return
}
_, port, _ := net.SplitHostPort(c.LocalAddr().String())
if parsedURL.Port() != "" && parsedURL.Port() != port {
sendError(c, ProxyRequestRefused, "Wrong port")
return
}
for i := 0; i < len(config.Domain); i++ {
if config.Domain[i].Name == parsedURL.Hostname() {
handleRequest(c, i, parsedURL)
return
}
}
sendError(c, ProxyRequestRefused, fmt.Sprintf("Host not found '%s'",
parsedURL.Host))
}