Refactor Gemini protocol implementation and improve server architecture

- Move gemini URL parsing from common/ to gemini/ package
- Add structured status codes in gemini/status_codes.go
- Improve error handling with proper Gemini status codes
- Update configuration field naming (Listen -> ListenAddr)
- Add UTF-8 validation for URLs
- Enhance security with better path validation
- Add CLAUDE.md for development guidance
- Include example content in srv/ directory
- Update build system to use standard shell
This commit is contained in:
antanst
2025-06-06 15:02:25 +03:00
parent a426edb1f6
commit 2ead66f012
10 changed files with 174 additions and 36 deletions

18
main.go
View File

@@ -14,12 +14,16 @@ import (
"time"
"gemserve/config"
"gemserve/gemini"
"gemserve/server"
logging "git.antanst.com/antanst/logging"
"git.antanst.com/antanst/uid"
"git.antanst.com/antanst/xerrors"
)
// This channel is for handling fatal errors
// from anywhere in the app. The consumer
// should log and panic.
var fatalErrors chan error
func main() {
@@ -37,7 +41,7 @@ func main() {
func runApp() error {
logging.LogInfo("Starting up. Press Ctrl+C to exit")
listenHost := config.CONFIG.Listen
listenAddr := config.CONFIG.ListenAddr
signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
@@ -45,7 +49,7 @@ func runApp() error {
fatalErrors = make(chan error)
go func() {
err := startServer(listenHost)
err := startServer(listenAddr)
if err != nil {
fatalErrors <- xerrors.NewError(err, 0, "Server startup failed", true)
}
@@ -62,7 +66,7 @@ func runApp() error {
}
}
func startServer(listenHost string) (err error) {
func startServer(listenAddr string) (err error) {
cert, err := tls.LoadX509KeyPair("certs/server.crt", "certs/server.key")
if err != nil {
return xerrors.NewError(fmt.Errorf("failed to load certificate: %w", err), 0, "Certificate loading failed", true)
@@ -73,7 +77,7 @@ func startServer(listenHost string) (err error) {
MinVersion: tls.VersionTLS12,
}
listener, err := tls.Listen("tcp", listenHost, tlsConfig)
listener, err := tls.Listen("tcp", listenAddr, tlsConfig)
if err != nil {
return xerrors.NewError(fmt.Errorf("failed to create listener: %w", err), 0, "Listener creation failed", true)
}
@@ -87,7 +91,7 @@ func startServer(listenHost string) (err error) {
}
}(listener)
logging.LogInfo("Server listening on %s", listenHost)
logging.LogInfo("Server listening on %s", listenAddr)
for {
conn, err := listener.Accept()
@@ -106,7 +110,7 @@ func startServer(listenHost string) (err error) {
fatalErrors <- asErr
return
} else {
logging.LogWarn("%s %s Connection failed: %d %s (%v)", connId, remoteAddr, asErr.Code, asErr.UserMsg, err)
logging.LogWarn("%s %s Connection failed: %v", connId, remoteAddr, err)
}
}
}()
@@ -157,7 +161,7 @@ func handleConnection(conn *tls.Conn, connId string, remoteAddr string) (err err
code = xErr.Code
responseMsg = xErr.UserMsg
} else {
code = 50
code = gemini.StatusPermanentFailure
responseMsg = "server error"
}
responseHeader = fmt.Sprintf("%d %s", code, responseMsg)