Skip to content

Instantly share code, notes, and snippets.

@foxcpp
Last active September 29, 2019 17:04
Show Gist options
  • Save foxcpp/56135560de7feaadd9a0d6b07c57b1c9 to your computer and use it in GitHub Desktop.
Save foxcpp/56135560de7feaadd9a0d6b07c57b1c9 to your computer and use it in GitHub Desktop.
Absolutely minimalistic webfs in Go
package main
import (
"errors"
"flag"
"log"
"net/http"
"os"
"path/filepath"
"strings"
)
// checkSymlink checks whether root/path doesn't contain symlinks that lead
// outside of the root directory.
func checkSymlink(root string, path string) error {
fullPath, err := filepath.EvalSymlinks(filepath.Join(root, path))
if err != nil {
return err
}
if !filepath.HasPrefix(fullPath, root) {
return errors.New("symlink leads outside of the root directory")
}
return nil
}
func main() {
addr := flag.String("addr", ":8080", "Address port to use (ADDR:PORT)")
tlsCert := flag.String("tls.cert", "", "TLS certificate to use (optional)")
tlsKey := flag.String("tls.key", "", "TLS key to use (optional)")
dir := flag.String("dir", "", "Directory to server instead of PWD")
flag.Parse()
if *dir == "" {
pwd, err := os.Getwd()
if err != nil {
log.Fatalln(err)
}
dir = &pwd
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
file := filepath.Join(*dir, r.URL.Path)
log.Printf(`%s "%s %s %s"`, strings.Split(r.RemoteAddr, ":")[0], r.Method, r.URL, r.Proto)
if err := checkSymlink(*dir, r.URL.Path); err != nil {
w.WriteHeader(403)
w.Write([]byte(err.Error()))
return
}
http.ServeFile(w, r, file)
})
if *tlsCert != "" && *tlsKey != "" {
log.Println("serving", *dir, "over", *addr, "with TLS")
if err := http.ListenAndServeTLS(*addr, *tlsCert, *tlsKey, nil); err != nil {
log.Fatalln(err)
}
return
}
log.Println("serving", *dir, "over", *addr)
if err := http.ListenAndServe(*addr, nil); err != nil {
log.Fatalln(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment