commit 9b99bd144225bbe8c2240ada9f545cba9e6cdc06 Author: Arzumify Date: Thu Jul 11 18:18:29 2024 +0100 Initial commit diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/httpserver.iml b/.idea/httpserver.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/.idea/httpserver.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..51ee430 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# HTTPServer + +This is a simple HTTP server meant to emulate python's SimpleHTTPServer module. + +## Usage + +```httpserver [-h] [--cgi] [-b ADDRESS] [-d DIRECTORY] [-p VERSION] [port]``` \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..a4e27c8 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module concord.hectabit.org/HectaBit/httpserver + +go 1.22.5 diff --git a/httpserver/Makefile b/httpserver/Makefile new file mode 100644 index 0000000..9e35ba7 --- /dev/null +++ b/httpserver/Makefile @@ -0,0 +1,19 @@ +# Run go build +DESTDIR = /usr + +all: httpserver + +httpserver: main.go + go build main.go + mv main httpserver + +clean: + rm -f httpserver + +.PHONY: all clean + +install: httpserver + cp -r httpserver $(DESTDIR)/bin + +uninstall: + rm -f $DESTDIR/bin/httpserver \ No newline at end of file diff --git a/httpserver/httpserver b/httpserver/httpserver new file mode 100755 index 0000000..1b376fb Binary files /dev/null and b/httpserver/httpserver differ diff --git a/httpserver/main.go b/httpserver/main.go new file mode 100644 index 0000000..7aa710d --- /dev/null +++ b/httpserver/main.go @@ -0,0 +1,90 @@ +package main + +import ( + "concord.hectabit.org/HectaBit/httpserver" + "fmt" + "os" + "strconv" + "strings" +) + +func handleErr(err error, errCode int) { + if err != nil { + if err.Error() == "address already in use" { + fmt.Println("OSError: [Errno 98] Address already in use") + os.Exit(1) + } else if err.Error() == "invalid port" { + fmt.Println("socket.gaierror: [Errno -8] Servname not supported for ai_socktype") + os.Exit(1) + } else if err.Error() == "permission denied" { + fmt.Println("PermissionError: [Errno 13] Permission denied") + os.Exit(1) + } else { + fmt.Println("Unknown error:", err) + os.Exit(errCode) + } + } else { + os.Exit(errCode) + } +} + +func main() { + if len(os.Args) < 2 { + err, errCode := httpserver.StartServer("8000", "./", "0.0.0.0", "1.0") + handleErr(err, errCode) + } else { + args := os.Args[1:] + protocolVer, path, address, port := "1.0", "./", "0.0.0.0", "8000" + for num, arg := range args { + if strings.Contains(arg, "-") { + if strings.Contains(arg, "-p") || strings.Contains(arg, "--protocol") { + if len(args) > num+1 { + protocolVer = args[num+1] + args = append(args[:num+1], args[num+2:]...) + } else { + fmt.Println("usage: httpserver [-h] [--cgi] [-b ADDRESS] [-d DIRECTORY] [-p VERSION] [port]\nhttpserver: error: argument -p/--protocol: expected one argument") + os.Exit(2) + } + } else if strings.Contains(arg, "-d") || strings.Contains(arg, "--directory") { + if len(args) > num+1 { + path = args[num+1] + args = append(args[:num+1], args[num+2:]...) + } else { + fmt.Println("usage: httpserver [-h] [--cgi] [-b ADDRESS] [-d DIRECTORY] [-p VERSION] [port]\nhttpserver: error: argument -d/--directory: expected one argument") + os.Exit(2) + } + } else if strings.Contains(arg, "-b") || strings.Contains(arg, "--bind") { + if len(args) > num+1 { + address = args[num+1] + args = append(args[:num+1], args[num+2:]...) + } else { + fmt.Println("usage: httpserver [-h] [--cgi] [-b ADDRESS] [-d DIRECTORY] [-p VERSION] [port]\nhttpserver: error: argument -b/--bind: expected one argument") + os.Exit(2) + } + } else if strings.Contains(arg, "-h") || strings.Contains(arg, "--help") { + fmt.Println("usage: httpserver [-h] [-b ADDRESS] [-d DIRECTORY] [-p VERSION] [port]\n\npositional arguments:\n port bind to this port (default: 8000)\n\noptions:\n -h, --help show this help message and exit\n -b ADDRESS, --bind ADDRESS\n bind to this address (default: all interfaces)\n -d DIRECTORY, --directory DIRECTORY\n serve this directory (default: current directory)\n -p VERSION, --protocol VERSION\n conform to this HTTP version (default: HTTP/1.0)") + os.Exit(0) + } else { + fmt.Println("usage: httpserver [-h] [-b ADDRESS] [-d DIRECTORY] [-p VERSION] [port]") + fmt.Println("httpserver: error: unrecognized arguments: " + arg) + os.Exit(2) + } + } else { + if len(args) >= num+1 { + if args[num] == arg { + _, err := strconv.Atoi(arg) + if err != nil { + fmt.Println("usage: httpserver [-h] [-b ADDRESS] [-d DIRECTORY] [-p VERSION] [port]") + fmt.Println("httpserver: error: argument port: invalid int value: '" + arg + "'") + os.Exit(2) + } else { + port = arg + } + } + } + } + } + err, errCode := httpserver.StartServer(port, path, address, protocolVer) + handleErr(err, errCode) + } +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..88f68c8 --- /dev/null +++ b/main.go @@ -0,0 +1,29 @@ +package httpserver + +import ( + "crypto/tls" + "errors" + "fmt" + "net/http" +) + +func StartServer(port string, path string, address string, protocolVer string) (error, int) { + var httpServer *http.Server + addressPort := address + ":" + port + fileServer := http.FileServer(http.Dir(path)) + fmt.Println("Serving HTTP on", address, "port", port, "(http://"+address+":"+port+"/) ...") + if protocolVer == "2.0" || protocolVer == "2" { + httpServer = &http.Server{Addr: addressPort, Handler: fileServer, TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler))} + } else { + httpServer = &http.Server{Addr: addressPort, Handler: fileServer} + } + err := httpServer.ListenAndServe() + if err != nil { + if err.Error() == "permission denied" || err.Error() == "listen tcp "+addressPort+": bind: permission denied" { + return errors.New("permission denied"), 1 + } else { + return err, 1 + } + } + return nil, 0 +}