package http
import (
"fmt"
"html/template"
"io/ioutil"
"net/http"
"strings"
"git.darknebu.la/emile/faila/src/structs"
"github.com/gorilla/mux"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
)
// Server defines and runs an HTTP server
func Server() {
r := mux.NewRouter()
// static js / css hosting
static := r.PathPrefix("/static/").Subrouter()
fs := http.FileServer(http.Dir("./hosted/static"))
static.PathPrefix("/").Handler(http.StripPrefix("/static/", fs))
t := r.PathPrefix("/").Subrouter()
t.PathPrefix("/").HandlerFunc(pathHandler)
// get the ip and port from the config
bindIP := viper.GetString("server.bindip")
listenPort := viper.GetString("server.listenport")
// define the http server
httpServer := http.Server{
Addr: fmt.Sprintf("%s:%s", bindIP, listenPort),
Handler: r,
}
logrus.Warnf("HTTP server defined listening on %s:%s", bindIP, listenPort)
logrus.Fatal(httpServer.ListenAndServe())
}
func pathHandler(w http.ResponseWriter, r *http.Request) {
var content map[string]interface{}
content = make(map[string]interface{})
breadcrumbsList := breadcrumbs(r)
content["Breadcrumbs"] = breadcrumbsList
root := viper.GetString("server.root")
requestURI := fmt.Sprintf("%s%s", root, r.RequestURI)
logrus.Infof("requestURI: %s", requestURI)
logrus.Infof("r.RequestURI: %s", r.RequestURI)
// get all files in the request dir
files, err := ioutil.ReadDir(requestURI)
if err != nil {
logrus.Warn(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
// define the items (files and dirs)
var items structs.Items
var dirCount int = 0
var fileCount int = 0
for _, f := range files {
// get the file or dirs modtime and format it in a readable way as
// described in the config
modTime := f.ModTime()
if viper.GetString("time.format") == "" {
logrus.Fatalf("Please insert a format for the time in the config (time.format), see the README for more information.")
}
humanModTime := modTime.Format(viper.GetString("time.format"))
// define the file or dir's url
var url string
if r.RequestURI != "/" {
url = fmt.Sprintf("%s/%s", r.RequestURI, f.Name())
} else {
url = fmt.Sprintf("/%s", f.Name())
}
// define the file or dir
item := structs.Item{
Name: f.Name(),
HumanSize: f.Size(),
URL: url,
HumanModTime: humanModTime,
IsSymlink: false,
Size: "0",
}
// if it is a dir, say so
if f.IsDir() == true {
item.IsDir = true
dirCount++
}
items = append(items, item)
}
// add the items to the content map
content["Items"] = items
// ad the file and dir count to the contents map
content["NumDirs"] = dirCount
content["NumFiles"] = fileCount
// if there are more than one breadcrumb, define the uppath as the second
// last breadcrumb
// I did this, because somehow things broke when simply using ".." in
// combination with hidden folders
if len(breadcrumbsList) > 1 {
content["UpPath"] = breadcrumbsList[len(breadcrumbsList)-2].Link
} else {
content["UpPath"] = ".."
}
// In the caddy
content["ItemsLimitedTo"] = 100000000000
// define the sort order manually
// TODO: handle this correctly
content["Sort"] = "namedirfirst"
content["Order"] = "desc"
// if we're not at the root, we can still go futher down!
if r.RequestURI != "/" {
content["CanGoUp"] = "true"
}
// define a new template to render the challenges in
t := template.New("")
t, err = t.ParseGlob("./hosted/tmpl/*.html")
if err != nil {
logrus.Warn(err)
return
}
t.ExecuteTemplate(w, "index", content)
}
// breadcrumbs get's the breadcrumbs from the request
func breadcrumbs(r *http.Request) structs.Breadcrumbs {
logrus.Debugf("----------------------------------------------------------")
logrus.Debugf("%s\n", r.RequestURI)
request := r.RequestURI
// mitigate path traversals
strippedRequest := strings.Replace(request, "..", "", -1)
if request != "/" {
strippedRequest = strings.TrimRight(strippedRequest, "/")
}
// continue without the first slash, as it produces an unused field that has
// no use
crumbs := strings.Split(strippedRequest[1:], "/")
// build the breadcrumbs from the split RequestURI
var breadcrumbs structs.Breadcrumbs
for i, crumb := range crumbs {
text := crumb
// the link is defined as the text until the given crumb
link := strings.Join(crumbs[:i+1], "/")
resultCrumb := structs.Crumb{
Text: text,
Link: fmt.Sprintf("/%s", link),
}
breadcrumbs = append(breadcrumbs, resultCrumb)
}
return breadcrumbs
}