diff options
author | Thomas Voss <mail@thomasvoss.com> | 2025-08-16 20:07:18 +0200 |
---|---|---|
committer | Thomas Voss <mail@thomasvoss.com> | 2025-08-16 20:07:18 +0200 |
commit | 7cf51e6fcd1cce954ffef5bbb71ae865b0d4d5d8 (patch) | |
tree | cb71c6e15a5caf73ab860cde170300761c2cad63 /mpaste.go | |
parent | f9d7145f52004048f7c309f92f591db885803e02 (diff) |
Diffstat (limited to 'mpaste.go')
-rw-r--r-- | mpaste.go | 152 |
1 files changed, 77 insertions, 75 deletions
@@ -2,6 +2,7 @@ package main import ( "bufio" + "cmp" "fmt" "io" "io/ioutil" @@ -12,11 +13,11 @@ import ( "strings" "sync" + "git.sr.ht/~mango/opts/v2" "github.com/alecthomas/chroma/v2/formatters/html" "github.com/alecthomas/chroma/v2/lexers" "github.com/alecthomas/chroma/v2/styles" "github.com/dgrijalva/jwt-go" - "git.thomasvoss.com/getgopt" ) const ( @@ -40,12 +41,12 @@ var ( func usage() { fmt.Fprintf(os.Stderr, - "Usage: %s [-c file] [-f directory] [-i file] [-u file] domain port\n", + "Usage: %s [-c file] [-i file] [-p directory] [-u file] domain port\n", os.Args[0]) os.Exit(1) } -func die(e interface{}) { +func die(e any) { fmt.Fprintln(os.Stderr, e) os.Exit(1) } @@ -165,87 +166,92 @@ func syntaxHighlighting(w http.ResponseWriter, r *http.Request) { } } -func endpoint(w http.ResponseWriter, r *http.Request) { - switch r.Method { - case http.MethodGet: - switch isValidUrl(r.URL.Path[1:]) { - case urlHomepage: - http.ServeFile(w, r, indexFile) - case urlInvalid: - writeHeader(w, http.StatusNotFound, "") - return - case urlSyntax: - w.Header().Set("Content-Type", "text/html; charset=utf-8") - syntaxHighlighting(w, r) - case urlValid: - w.Header().Set("Content-Type", "text/plain; charset=utf-8") - http.ServeFile(w, r, filePrefix+r.URL.Path[1:]) - } - case http.MethodPost: - if secretKey != "" && !validateToken(r) { - writeHeader(w, http.StatusForbidden, "") - return - } - - file, _, err := r.FormFile("data") - defer file.Close() - if err != nil { - writeHeader(w, http.StatusInternalServerError, "Failed to parse form") - return - } +func get(w http.ResponseWriter, r *http.Request) { + switch isValidUrl(r.URL.Path[1:]) { + case urlHomepage: + http.ServeFile(w, r, indexFile) + case urlInvalid: + writeHeader(w, http.StatusNotFound, "") + return + case urlSyntax: + w.Header().Set("Content-Type", "text/html; charset=utf-8") + syntaxHighlighting(w, r) + case urlValid: + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + http.ServeFile(w, r, filePrefix+r.URL.Path[1:]) + } +} - mutex.Lock() - defer mutex.Unlock() +func post(w http.ResponseWriter, r *http.Request) { + if secretKey != "" && !validateToken(r) { + writeHeader(w, http.StatusForbidden, "") + return + } - fname := filePrefix + strconv.Itoa(counter) - nfile, err := os.Create(fname) - defer nfile.Close() - if err != nil { - writeHeader(w, http.StatusInternalServerError, "Failed to create file") - return - } + file, _, err := r.FormFile("data") + defer file.Close() + if err != nil { + writeHeader(w, http.StatusInternalServerError, "Failed to parse form") + return + } - if _, err = io.Copy(nfile, file); err != nil { - writeHeader(w, http.StatusInternalServerError, "Failed to write file") - return - } + mutex.Lock() + defer mutex.Unlock() - if err = os.WriteFile(counterFile, []byte(strconv.Itoa(counter+1)), 0644); err != nil { - writeHeader(w, http.StatusInternalServerError, "Failed to update counter") - return - } + fname := filePrefix + strconv.Itoa(counter) + nfile, err := os.Create(fname) + defer nfile.Close() + if err != nil { + writeHeader(w, http.StatusInternalServerError, "Failed to create file") + return + } - w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, domain+"/%d\n", counter) + if _, err = io.Copy(nfile, file); err != nil { + writeHeader(w, http.StatusInternalServerError, "Failed to write file") + return + } - counter++ - default: - writeHeader(w, http.StatusMethodNotAllowed, "Only GET and POST requests are supported") + if err = os.WriteFile(counterFile, []byte(strconv.Itoa(counter+1)), 0644); err != nil { + writeHeader(w, http.StatusInternalServerError, "Failed to update counter") + return } + + w.WriteHeader(http.StatusOK) + fmt.Fprintf(w, domain+"/%d\n", counter) + + counter++ } func main() { - for opt := byte(0); getgopt.Getopt(len(os.Args), os.Args, ":c:f:i:u:", &opt); { - switch opt { + flags, rest, err := opts.GetLong(os.Args, []opts.LongOpt{ + {Short: 'c', Long: "counter-file", Arg: opts.Required}, + {Short: 'i', Long: "index", Arg: opts.Required}, + {Short: 'p', Long: "prefix", Arg: opts.Required}, + {Short: 'u', Long: "user-file", Arg: opts.Required}, + }) + if err != nil { + fmt.Fprintf(os.Stderr, "%s: %s\n", os.Args[0], err) + usage() + } + + for _, f := range flags { + switch f.Key { case 'c': - counterFile = getgopt.Optarg - case 'f': - filePrefix = getgopt.Optarg + counterFile = f.Value case 'i': - indexFile = getgopt.Optarg + indexFile = f.Value + case 'p': + filePrefix = f.Value case 'u': - userFile = getgopt.Optarg - default: - usage() + userFile = f.Value } } - argv := os.Args[getgopt.Optind:] - if len(argv) != 2 { + if len(rest) != 2 { usage() } - domain = argv[0] - port := argv[1] + domain = rest[0] + port := rest[1] if filePrefix == "" { filePrefix = "files/" @@ -253,13 +259,8 @@ func main() { filePrefix += "/" } - if counterFile == "" { - counterFile = "counter" - } - - if indexFile == "" { - indexFile = "index.html" - } + counterFile = cmp.Or(counterFile, "counter") + indexFile = cmp.Or(indexFile, "index.html") if _, err := os.Stat(indexFile); os.IsNotExist(err) { die(err) @@ -281,6 +282,7 @@ func main() { counter, _ = strconv.Atoi(string(data)) } - http.HandleFunc("/", endpoint) + http.HandleFunc("GET /", get) + http.HandleFunc("POST /", post) die(http.ListenAndServe(":"+port, nil)) -} +}
\ No newline at end of file |