💾 Archived View for tozip.chickenkiller.com › sss.go captured on 2023-03-20 at 17:59:53.
⬅️ Previous capture (2022-07-16)
-=-=-=-=-=-=-
/* 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()) } }