diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/go.mod | 10 | ||||
-rw-r--r-- | server/go.sum | 17 | ||||
-rw-r--r-- | server/main.go | 48 | ||||
-rw-r--r-- | server/md-page.go | 95 |
4 files changed, 170 insertions, 0 deletions
diff --git a/server/go.mod b/server/go.mod new file mode 100644 index 0000000..6328a03 --- /dev/null +++ b/server/go.mod @@ -0,0 +1,10 @@ +module sanine.net/sanine.net-server + +go 1.19 + +require ( + github.com/russross/blackfriday/v2 v2.1.0 + github.com/sirupsen/logrus v1.9.0 +) + +require golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect diff --git a/server/go.sum b/server/go.sum new file mode 100644 index 0000000..900e85f --- /dev/null +++ b/server/go.sum @@ -0,0 +1,17 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/server/main.go b/server/main.go new file mode 100644 index 0000000..63aadb5 --- /dev/null +++ b/server/main.go @@ -0,0 +1,48 @@ +package main + +import ( + "fmt" + "net/http" + "flag" + "path/filepath" + log "github.com/sirupsen/logrus" +) + + +func main() { + log.SetFormatter(&log.TextFormatter{ + FullTimestamp: true, + }); + + pathFlag := flag.String( + "path", "data", "the path to load site data from", + ); + addrFlag := flag.String( + "addr", "127.0.0.1:8080", "the address to serve from", + ); + flag.Parse(); + log.Infof("data path: %v", *pathFlag); + log.Infof("serving from %v", *addrFlag); + + mux := http.NewServeMux() + mux.HandleFunc("/ip", func(w http.ResponseWriter, req *http.Request) { + fmt.Fprintf(w, "%v", req.RemoteAddr); + }); + mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { + if req.URL.Path != "/" { + path := filepath.Join(*pathFlag, req.URL.Path); + Serve(w, req, path); + } else { + Serve(w, req, filepath.Join(*pathFlag, "index.md")); + } + }); + + server := http.Server{ + Addr: *addrFlag, + Handler: mux, + }; + err := server.ListenAndServe(); + if err != nil { + log.Fatal(err); + } +} diff --git a/server/md-page.go b/server/md-page.go new file mode 100644 index 0000000..8b378c5 --- /dev/null +++ b/server/md-page.go @@ -0,0 +1,95 @@ +package main + +import ( + "os" + "strings" + "net/http" + log "github.com/sirupsen/logrus" + md "github.com/russross/blackfriday/v2" +) + + +func ServeForbidden(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(403); + w.Write([]byte("403 forbidden")); +} + + +func ServeNotFound(w http.ResponseWriter, r *http.Request) { + http.NotFound(w, r); +} + + +func RenderMarkdown(path string) ([]byte, error) { + data, err := os.ReadFile(path); + if err != nil { + return []byte{}, err; + } + return md.Run(data), nil; +} + + +func ServeMarkdown(w http.ResponseWriter, r *http.Request, path string) (int, error) { + page, err := RenderMarkdown(path); + if err != nil { + return 404, err; + } + w.WriteHeader(200); + w.Write(page); + return 200, nil; +} + +func ServeFile(w http.ResponseWriter, r *http.Request, path string) (int, error) { + if strings.Contains(r.URL.Path, "..") { + // reject requests with ".." in the URL + return 403, nil; + } + data, err := os.ReadFile(path); + if err != nil { + return 404, err; + } + + w.WriteHeader(200); + w.Write(data); + return 200, nil; +} + + +func IsMarkdown(path string) bool { + return strings.HasSuffix(path, ".md"); +} + + +func Serve(w http.ResponseWriter, r *http.Request, path string) { + var status int; + var err error; + + if IsMarkdown(path) { + // render and serve markdown content + status, err = ServeMarkdown(w, r, path); + } else { + // serve raw file + status, err = ServeFile(w, r, path); + } + + if status == 200 { + log.Infof( + "%v 200\t%v <- %v", + r.Method, r.RemoteAddr, r.URL.Path, + ); + } else { + log.Errorf( + "%v %v\t%v <- %v: %v", + r.Method, status, r.RemoteAddr, r.URL.Path, err, + ); + switch status { + case 403: + ServeForbidden(w, r); + case 404: + ServeNotFound(w, r); + default: + w.WriteHeader(status); + w.Write([]byte("error")); + } + } +} |