diff --git a/fetch.go b/fetch.go deleted file mode 100644 index bea18d0..0000000 --- a/fetch.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "os" - "strings" -) - -func fetchFileContents(filepath string) ([]byte, error) { - if filepath == "/" { - filepath = "." - } else { - filepath_relative, _ := strings.CutPrefix(filepath, "/") - filepath = filepath_relative - } - fileinfo, err := os.Stat(filepath) - if err != nil { - return nil, err - } - if fileinfo.IsDir() { - filepath += "/index.html" - } - return os.ReadFile(filepath) - -} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..68e91f0 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module com.github/shlldev/miniws + +go 1.22.2 + +require github.com/akamensky/argparse v1.4.0 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..5bf91e2 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/akamensky/argparse v1.4.0 h1:YGzvsTqCvbEZhL8zZu2AiA5nq805NZh75JNj4ajn1xc= +github.com/akamensky/argparse v1.4.0/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA= diff --git a/index.html b/index.html new file mode 100644 index 0000000..2a90e08 --- /dev/null +++ b/index.html @@ -0,0 +1,11 @@ + + + + + + +

+ test +

+ + \ No newline at end of file diff --git a/log.go b/log.go deleted file mode 100644 index 7e461fd..0000000 --- a/log.go +++ /dev/null @@ -1,62 +0,0 @@ -package main - -import ( - "fmt" - "log" - "os" -) - -func logIfError(err error) bool { - if err != nil { - logError(err.Error()) - return true - } - return false -} - -// func logAccess( -// remoteAddr, remoteUser, timeLocal, request, status, -// bodyBytesSent, httpReferrer, httpUseragent string, -// ) { -// out := fmt.Sprintf("%v - %v - [%v] \"%v\" %v %v \"%v\" \"%v\"\n", -// remoteAddr, remoteUser, timeLocal, request, status, bodyBytesSent, -// httpReferrer, httpUseragent, -// ) -// file, err := os.OpenFile(PATH_ACCESSLOG, os.O_APPEND|os.O_WRONLY, os.ModeType) -// if err != nil { -// log.Println("couldn't open log access file at", PATH_ACCESSLOG) -// } -// defer file.Close() -// file.WriteString(out) -// } - -func logAccess( - remoteAddr, identifier, authuser, timestamp, request, - status, bytesSent string, -) { - out := fmt.Sprintf("%v %v %v [%v] \"%v\" %v %v\n", - remoteAddr, identifier, authuser, timestamp, request, status, bytesSent, - ) - file, err := os.OpenFile(PATH_ACCESSLOG, os.O_APPEND|os.O_WRONLY, os.ModeType) - if err != nil { - log.Println("couldn't open log access file at", PATH_ACCESSLOG) - } - defer file.Close() - file.WriteString(out) -} - -func logError(str string) { - file, err := os.OpenFile(PATH_ERRORLOG, os.O_APPEND|os.O_WRONLY, os.ModeType) - if err != nil { - log.Println("couldn't open log error file at", PATH_ACCESSLOG) - } - defer file.Close() - file.WriteString(str + "\n") -} - -func getOrDash(str string) string { - if str == "" { - return "-" - } - return str -} diff --git a/main.go b/main.go index 2a8af12..0bb5dd3 100644 --- a/main.go +++ b/main.go @@ -1,28 +1,52 @@ package main import ( + "fmt" "log" "net/http" + "os" "strconv" "strings" "time" + + "github.com/akamensky/argparse" ) const ( - PATH_ACCESSLOG string = "access.log" - PATH_ERRORLOG string = "error.log" + PATH_ACCESSLOG string = "access.log" + PATH_ERRORLOG string = "error.log" + FLAGS_LOG_OPEN int = os.O_APPEND | os.O_WRONLY | os.O_CREATE + PERMS_LOG_OPEN os.FileMode = os.ModeType | os.ModePerm ) +var _logFolder string = "" + func main() { + + parser := argparse.NewParser("miniws", "") + port := parser.String("p", "port", &argparse.Options{Default: "8040"}) + logFolder := parser.String("l", "logs-folder", &argparse.Options{Default: "logs"}) + + err := parser.Parse(os.Args) + if err != nil { + // In case of error print error and print usage + // This can also be done by passing -h or --help flags + fmt.Print(parser.Usage(err)) + } + + _logFolder = *logFolder + http.HandleFunc("/{resource...}", get) - log.Println("Server started") - http.ListenAndServe(":8080", nil) + log.Println("Server started on port " + *port) + http.ListenAndServe(":"+*port, nil) } func get(writer http.ResponseWriter, req *http.Request) { fetchedData, fetchErr := fetchFileContents(req.URL.Path) - respStatusCode := int(200) - var sentBytes int = 0 + + sentBytes := 0 + respStatusCode := http.StatusOK + if logIfError(fetchErr) { respStatusCode = http.StatusNotFound writer.WriteHeader(respStatusCode) @@ -30,12 +54,86 @@ func get(writer http.ResponseWriter, req *http.Request) { sentBytesCount, _ := writer.Write(fetchedData) sentBytes = sentBytesCount } - logAccess(strings.Split(req.RemoteAddr, ":")[0], "-", getOrDash(req.URL.User.Username()), time.Now().Format("02/Jan/2006:03:04:05 -0700"), - req.Method+" "+req.URL.Path+" "+getHttpString(req.ProtoMajor, req.ProtoMinor), strconv.Itoa(respStatusCode), - strconv.Itoa(sentBytes), + + logAccess( + strings.Split(req.RemoteAddr, ":")[0], //remote address + "-", //identifier (can't get) + getOrDash(req.URL.User.Username()), //username + time.Now().Format("02/Jan/2006:15:04:05 -0700"), //timestamp + req.Method+" "+req.URL.Path+" "+getHttpString(req.ProtoMajor, req.ProtoMinor), //HTTP version + strconv.Itoa(respStatusCode), //response code + strconv.Itoa(sentBytes), //# of sent bytes + req.Referer(), //Referer + req.UserAgent(), //User Agent ) } +func fetchFileContents(filepath string) ([]byte, error) { + if filepath == "/" { + filepath = "." + } else { + filepath_relative, _ := strings.CutPrefix(filepath, "/") + filepath = filepath_relative + } + fileinfo, err := os.Stat(filepath) + if err != nil { + return nil, err + } + if fileinfo.IsDir() { + filepath += "/index.html" + } + return os.ReadFile(filepath) + +} + +// returns error != nil +func logIfError(err error) bool { + if err != nil { + logError(err.Error()) + return true + } + return false +} + +func logAccess( + remoteAddr, identifier, authuser, timestamp, request, + status, bytesSent, referer, user_agent string, +) { + out := fmt.Sprintf("%v %v %v [%v] \"%v\" %v %v \"%v\" \"%v\"\n", + remoteAddr, identifier, authuser, timestamp, request, status, bytesSent, referer, user_agent, + ) + os.Mkdir(_logFolder, os.ModeDir|os.ModePerm) + file, err := os.OpenFile(assureSlash(_logFolder)+PATH_ACCESSLOG, FLAGS_LOG_OPEN, PERMS_LOG_OPEN) + + if err != nil { + log.Println("couldn't open log access file at", assureSlash(_logFolder)+PATH_ACCESSLOG) + } + defer file.Close() + file.WriteString(out) +} + +func logError(str string) { + file, err := os.OpenFile(assureSlash(_logFolder)+PATH_ERRORLOG, FLAGS_LOG_OPEN, PERMS_LOG_OPEN) + os.Mkdir(_logFolder, os.ModeDir|os.ModePerm) + + if err != nil { + log.Println("couldn't open log error file at", assureSlash(_logFolder)+PATH_ERRORLOG) + } + defer file.Close() + file.WriteString(str + "\n") +} + func getHttpString(major, minor int) string { return "HTTP/" + strconv.Itoa(major) + "." + strconv.Itoa(minor) } + +func getOrDash(str string) string { + if str == "" { + return "-" + } + return str +} + +func assureSlash(str string) string { + return strings.TrimSuffix(str, "/") + "/" +}