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 }