💾 Archived View for tozip.chickenkiller.com › sss.go captured on 2023-06-16 at 16:19:45. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-03-20)
-=-=-=-=-=-=-
/* simple server for the spartan protocol
*/
package main
import (
"bufio"
"errors"
"fmt"
"net"
"os"
"path/filepath"
"strings"
)
const (
//CONN_HOST = "localhost"
//CONN_HOST = "0.0.0.0"
//CONN_HOST = ""
CONN_HOST = "127.0.0.1"
//CONN_HOST = "192.168.0.27"
//CONN_HOST = "blinkyshark.chickenkiller.com"
CONN_PORT = "3000"
CONN_TYPE = "tcp"
DATA_DIR = "/home/pi/repos/gemtext"
)
func main() {
// Listen for incoming connections.
l, err := net.Listen(CONN_TYPE, CONN_HOST+":"+CONN_PORT)
if err != nil {
fmt.Println("Error listening:", err.Error())
os.Exit(1)
}
// Close the listener when the application closes.
defer l.Close()
fmt.Println("Listening on " + CONN_HOST + ":" + CONN_PORT)
for {
// Listen for an incoming connection.
conn, err := l.Accept()
if err != nil {
fmt.Println("Error accepting: ", err.Error())
os.Exit(1)
}
// Handle connections in a new goroutine.
go handleRequest(conn)
}
}
func get_path(conn net.Conn) (string, error) {
oops := func(msg string) (string, error) { return "", errors.New(msg) }
buf := make([]byte, 1024) // buffer to hold incoming data
reqLen, err := conn.Read(buf) // Read the incoming connection into the buffer.
//fmt.Println("reqLen:", reqLen)
if err != nil { return "", err }
request := string(buf[:reqLen])
request = strings.TrimRight(request, "\r\n")
fields := strings.Fields(request)
if len(fields) != 3 {
str := "Bad request. Expected 3 fields, got '" + request + "'"
fmt.Println(str)
return oops(str)
}
path_in := fields[1]
if path_in == "/" { path_in = "index.gmi" }
path, err := filepath.Abs(DATA_DIR + "/" + path_in)
if err != nil { return "", err }
fmt.Println("path requested:", path)
// check for out-of-directory stuff
if len(path) < len(DATA_DIR) { return oops("path name is too short") }
if DATA_DIR != path[0:len(DATA_DIR)] { return oops("data root violated") }
info, err := os.Stat(path)
if err != nil { return "", err }
if info.IsDir() { return oops("Won't serve directories") }
fmt.Println("server=", fields[0])
fmt.Println("loc=", path)
fmt.Println("Received request ", string(buf[0:reqLen]))
return path, err
}
// Handles incoming requests.
func handleRequest(conn net.Conn) {
defer conn.Close()
oops := func(err_str string) {
err_str = "4 " + err_str;
fmt.Println(err_str)
conn.Write([]byte(err_str + "\r\n"))
}
pathname, err := get_path(conn)
if err != nil { oops(err.Error()) ; return }
fp, err := os.Open(pathname)
if err != nil { oops("file not found") ; return }
defer fp.Close()
response := "2 text/gemini"
if len(pathname) < 4 || pathname[len(pathname)-4:] != ".gmi" {
response = "2 text/plain; charset=utf-8"
}
conn.Write([]byte(response + "\r\n"))
scanner := bufio.NewScanner(fp)
for scanner.Scan() {
txt1 := scanner.Text()
//fmt.Println([]byte(txt1))
txt1 += "\r\n"
conn.Write([]byte(txt1))
}
if err := scanner.Err(); err != nil { oops(err.Error()) }
}