💾 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

View Raw

More Information

⬅️ Previous capture (2023-03-20)

🚧 View Differences

-=-=-=-=-=-=-

/* 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()) }

}