--- /dev/null
+package main
+
+import (
+ "database/sql"
+ "flag"
+ "fmt"
+ _ "github.com/mattn/go-sqlite3"
+ "io"
+ "log"
+ "net/http"
+ "net/url"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+const (
+ DefaultFormFileKey = "fileToUpload"
+ DefaultUploadPath = "/tmp"
+ DefaultUploadPrefix = "/upload"
+ DefaultRootIndex = "index.html"
+)
+
+var FormFileKey = flag.String("k", DefaultFormFileKey, "FormFileKey")
+var UploadPath = flag.String("u", DefaultUploadPath, "UploadPath")
+var UploadPrefix = flag.String("p", DefaultUploadPrefix, "UploadPrefix")
+var RootIndex = flag.String("i", DefaultRootIndex, "RootIndex")
+var Help = flag.Bool("h", false, "Show usage")
+
+func urlEscape(s string) string {
+ url := url.URL{Path: s}
+ return url.String()
+}
+
+func getFromDB(name string) (string, error) {
+ content := ""
+ db, err := sql.Open("sqlite3", "golfex.sqlite")
+ if err == nil {
+ defer db.Close()
+ var stmt *sql.Stmt
+ stmt, err = db.Prepare("SELECT content FROM docroot WHERE name = ?")
+ if nil == err {
+ defer stmt.Close()
+ err = stmt.QueryRow(name).Scan(&content)
+ }
+ }
+ return content, err
+}
+
+func rootHF(w http.ResponseWriter, r *http.Request) {
+ log.Print(r.RemoteAddr, " ", r.Method, " ", r.URL.String())
+ if http.MethodGet == r.Method {
+ //http module does plenty of cleaning on r.URL.Path
+ //so this should be "safe"
+ docName := strings.TrimLeft(r.URL.String(), "/")
+ if "" == docName {
+ docName = *RootIndex
+ }
+ //check if this is upload file request
+ if strings.HasPrefix(r.URL.String(), *UploadPrefix) {
+ upath := filepath.Join(*UploadPath, strings.Replace(r.URL.String(), *UploadPrefix, "", 1))
+ log.Print("Serving ", upath)
+ //only here because we want to do dir listing
+ //otherwise docName = upath should've done it
+ http.ServeFile(w, r, upath)
+ return
+ }
+ log.Print("Final docName: ", docName)
+ //see if there is a local file and serve it
+ fio, err := os.Stat(docName)
+ if (nil == err) && (fio.Mode().IsRegular()) {
+ log.Print("Serving local file")
+ http.ServeFile(w, r, docName)
+ return
+ }
+ log.Print("Serving from DB")
+ var content string
+ content, err = getFromDB(docName)
+ if err == nil {
+ w.Header().Add("Content-Length", fmt.Sprintf("%d", len(content)))
+ w.WriteHeader(http.StatusOK)
+ io.WriteString(w, content)
+ } else {
+ log.Print("DB lookup failed: ", err)
+ http.Error(w, "404 Not Found", http.StatusNotFound)
+ }
+ } else {
+ if http.MethodPost == r.Method {
+ ufile, mh, err := r.FormFile(*FormFileKey)
+ if nil == err {
+ defer ufile.Close()
+ of_dump, of_err := os.OpenFile(filepath.Join(*UploadPath, mh.Filename), os.O_CREATE|os.O_WRONLY, 0644)
+ if nil == of_err {
+ defer of_dump.Close()
+ io.Copy(of_dump, ufile)
+ log.Printf("Saved %v bytes to %v\n", mh.Size, mh.Filename)
+ w.WriteHeader(http.StatusOK)
+ io.WriteString(w, "Success!")
+ //fmt.Fprintf(w, "File name: %s<br>\n", mh.Filename);
+ //fmt.Fprintf(w, "File size: %v bytes<br>\n", mh.Size);
+ } else {
+ err = of_err
+ }
+ }
+ if nil != err {
+ w.WriteHeader(http.StatusInternalServerError)
+ fmt.Fprintf(w, "Error: %v", strings.Replace(err.Error(), *UploadPath, *UploadPrefix, -1))
+ log.Print(err)
+ }
+ }
+ }
+}
+
+func main() {
+ flag.Parse()
+ if *Help {
+ fmt.Printf("Usage: \n")
+ flag.PrintDefaults()
+ return
+ }
+ fmt.Printf("Current settings: \n")
+ flag.VisitAll(func(f *flag.Flag) { fmt.Printf("%v: %v\n", f.Usage, f.Value) })
+ http.HandleFunc("/", rootHF)
+ log.Fatal(http.ListenAndServe(":8000", nil))
+}