Browse Source

Updates to working/tested fileserver

master
sloum 2 years ago
parent
commit
f78c073a41
  1. 3
      .gitignore
  2. 0
      config.go.def
  3. 264
      main.go

3
.gitignore vendored

@ -0,0 +1,3 @@
turms
config.go
config.go.bak

0
config.go → config.go.def

264
main.go

@ -1,162 +1,172 @@
package main
import (
"bufio"
"fmt"
"io/ioutil"
"mime"
"net"
"net/url"
"os"
"path/filepath"
"strings"
"bufio"
"fmt"
"io/ioutil"
"mime"
"net"
"net/url"
"os"
"path/filepath"
"strings"
)
const (
VERSION float32 = 0.1
REQ_ERR string = "5 Invalid request\r\n"
SRV_ERR string = "4 Internal server error\r\n"
VERSION float32 = 0.1
REQ_ERR string = "5 Invalid request\r\n"
SRV_ERR string = "4 Internal server error\r\n"
)
var conf *config
func serveFile(path string, conn net.Conn) {
ext := filepath.Ext(path)
var mimeType string
if ext == ".gmi" || ext == ".gemini" {
mimeType = "text/gemini"
} else {
mimeType = mime.TypeByExtension(ext)
}
if mimeType == "" {
mimeType = "application/octet-stream"
}
contents, err := ioutil.ReadFile(path)
ext := filepath.Ext(path)
var mimeType string
if ext == ".gmi" || ext == ".gemini" {
mimeType = "text/gemini"
} else {
mimeType = mime.TypeByExtension(ext)
}
if mimeType == "" {
mimeType = "application/octet-stream"
}
contents, err := ioutil.ReadFile(path)
if err != nil {
fmt.Printf("5 - %s\n", string(path))
conn.Write([]byte(REQ_ERR))
}
conn.Write([]byte(fmt.Sprintf("20 %s\r\n", mimeType)))
conn.Write([]byte(fmt.Sprintf("2 %s\r\n", mimeType)))
conn.Write(contents)
fmt.Printf("2 - %s\n", string(path))
}
func getSystemPath(p string, full string) (string, error) {
hasTrailingSlash := strings.HasSuffix(p, "/")
var sysPath string
if strings.HasPrefix(p, conf.userPrefix) {
segments := strings.SplitN(p, "/", -1)
segments[1] = strings.Replace(p, conf.userPrefix, conf.userRoot, 1)
un := segments[2]
prefix := filepath.Join(conf.userPrefix, un, conf.userFolder)
if len(segments) > 3 {
suffix := strings.Join(segments[3:], "/")
sysPath = filepath.Join(prefix, suffix)
} else {
sysPath = prefix
}
} else {
sysPath = filepath.Join(conf.documentRoot, p)
}
fInfo, err := os.Stat(p)
if err != nil {
return "", fmt.Errorf(REQ_ERR)
}
// Fail if file does not exist or perms aren't right
hasTrailingSlash := strings.HasSuffix(p, "/")
var sysPath string
if strings.HasPrefix(p, conf.userPrefix) {
segments := strings.SplitN(p, "/", -1)
un := segments[2]
prefix := filepath.Join(conf.userRoot, un, conf.userFolder)
if len(segments) > 3 {
suffix := strings.Join(segments[3:], "/")
sysPath = filepath.Join(prefix, suffix)
} else {
sysPath = prefix
}
} else {
sysPath = filepath.Join(conf.documentRoot, p)
}
fInfo, err := os.Stat(sysPath)
if err != nil {
return "", fmt.Errorf(REQ_ERR)
}
// Fail if file does not exist or perms aren't right
if os.IsNotExist(err) || os.IsPermission(err) {
return "", fmt.Errorf(REQ_ERR)
return "", fmt.Errorf(REQ_ERR)
} else if err != nil {
return "", fmt.Errorf(SRV_ERR)
return "", fmt.Errorf(SRV_ERR)
} else if uint64(fInfo.Mode().Perm())&0444 != 0444 {
return "", fmt.Errorf(REQ_ERR)
return "", fmt.Errorf(REQ_ERR)
} else if fInfo.IsDir() {
if !hasTrailingSlash {
return "", fmt.Errorf("3 %s/\r\n", full)
}
}
if !hasTrailingSlash {
return "", fmt.Errorf("3 %s/\r\n", full)
}
}
return sysPath, nil
return sysPath, nil
}
func handleRequest(conn net.Conn) {
defer conn.Close()
defer conn.Close()
reader := bufio.NewReaderSize(conn, 1024)
reader := bufio.NewReaderSize(conn, 1024)
request, overflow, err := reader.ReadLine()
if overflow {
conn.Write([]byte("5 Request too long\r\n"))
return
fmt.Printf("5 - %s\n", string(request))
conn.Write([]byte(REQ_ERR))
return
} else if err != nil {
conn.Write([]byte("4 Internal server error\r\n"))
return
}
uri, err := url.Parse(string(request))
if err != nil {
conn.Write([]byte("5 Invalid request"))
return
}
if uri.Scheme == "" {
uri.Scheme = "mercury"
}
if uri.Scheme != "mercury" {
conn.Write([]byte("5 Invalid URL scheme"))
return
}
if reqHn := strings.Split(uri.Host, ":")[0]; reqHn != conf.host {
conn.Write([]byte("5 Invalid request"))
return
}
path, err := getSystemPath(uri.Path, uri.String())
if err != nil {
conn.Write([]byte(err.Error()))
return
}
fInfo, err := os.Stat(path)
if err != nil {
conn.Write([]byte(REQ_ERR))
return
}
if fInfo.IsDir() {
indexPath := filepath.Join(path, conf.indexFile)
indInfo, err := os.Stat(indexPath)
if err == nil && uint64(indInfo.Mode().Perm())&0444 == 0444 {
serveFile(indexPath, conn)
} else {
conn.Write([]byte(REQ_ERR))
}
return
}
serveFile(path, conn)
return
}
fmt.Printf("4 - %s", string(request))
conn.Write([]byte(SRV_ERR))
fmt.Println(err)
return
}
uri, err := url.Parse(string(request))
if err != nil {
fmt.Printf("5 - %s\n", string(request))
conn.Write([]byte(REQ_ERR))
return
}
if uri.Scheme == "" {
uri.Scheme = "mercury"
}
if uri.Scheme != "mercury" {
fmt.Printf("5 - %s\n", string(request))
conn.Write([]byte(REQ_ERR))
return
}
if reqHn := strings.Split(uri.Host, ":")[0]; reqHn != conf.host {
fmt.Printf("5 - %s\n", string(request))
conn.Write([]byte(REQ_ERR))
return
}
path, err := getSystemPath(uri.Path, uri.String())
if err != nil {
fmt.Println(err.Error())
conn.Write([]byte(err.Error()))
return
}
fInfo, err := os.Stat(path)
if err != nil {
fmt.Printf("5 - %s\n", string(request))
conn.Write([]byte(REQ_ERR))
return
}
if fInfo.IsDir() {
indexPath := filepath.Join(path, conf.indexFile)
indInfo, err := os.Stat(indexPath)
if err == nil && uint64(indInfo.Mode().Perm())&0444 == 0444 {
serveFile(indexPath, conn)
} else {
fmt.Printf("5 - %s\n", string(request))
conn.Write([]byte(REQ_ERR))
}
return
}
serveFile(path, conn)
return
}
func main() {
conf = makeConfig()
fmt.Printf("𐌕𐌖𐌓𐌌𐌑 - Version %f", VERSION)
if conf.host == "" {
fmt.Fprintln(os.Stderr, ">> No host is configured for this server\n>> Please recompile with a host name in config.go")
os.Exit(1)
}
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", conf.port))
if err != nil {
fmt.Fprintf(os.Stderr, "Error listening on port %d:\n%s\n", conf.port, err.Error())
os.Exit(1)
}
for {
conn, err := listener.Accept()
if err != nil {
fmt.Fprintf(os.Stderr, "Error listening on port %d:\n%s\n", conf.port, err.Error())
continue
}
go handleRequest(conn)
}
conf = makeConfig()
fmt.Printf("𐌕𐌖𐌓𐌌𐌑 - Version %.1f\n\n", VERSION)
if conf.host == "" {
fmt.Fprintln(os.Stderr, ">> No host is configured for this server\n>> Please recompile with a host name in config.go")
os.Exit(1)
}
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", conf.port))
if err != nil {
fmt.Fprintf(os.Stderr, "Error listening on port %d:\n%s\n", conf.port, err.Error())
os.Exit(1)
}
fmt.Printf("Listening on port %d\n", conf.port)
for {
conn, err := listener.Accept()
if err != nil {
fmt.Fprintf(os.Stderr, "Error listening on port %d:\n%s\n", conf.port, err.Error())
continue
}
go handleRequest(conn)
}
}

Loading…
Cancel
Save