ref: master
./main.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
package main import ( "errors" "flag" "fmt" "io" "io/fs" "log" "net/http" "os" "path/filepath" "strings" "github.com/google/uuid" ) func handleRoot(method, reqID string, w http.ResponseWriter) { if !(method == "GET" || method == "") { log.Printf("%s | 405", reqID) w.WriteHeader(http.StatusMethodNotAllowed) return } w.Write([]byte("cache works")) return } func getFile(storagePath, key, reqID string, w io.Writer) int { file, err := os.Open(filepath.Join(storagePath, key)) if err != nil { if errors.Is(err, fs.ErrNotExist) { return http.StatusNotFound } log.Printf("%s | while opening file to read: %v", reqID, err) return http.StatusInternalServerError } defer file.Close() _, err = io.Copy(w, file) if err != nil { log.Printf("%s | while copying to response: %v", reqID, err) return http.StatusInternalServerError } return http.StatusOK } func putFile(storagePath, key, reqID string, w io.Writer, body io.Reader) int { file, err := os.Create(filepath.Join(storagePath, key)) if err != nil { log.Printf("%s | while opening file to write: %v", reqID, err) return http.StatusInternalServerError } defer file.Close() _, err = io.Copy(file, body) if err != nil { log.Printf("%s | while copying to file: %v", reqID, err) return http.StatusInternalServerError } return http.StatusAccepted } func handler(w http.ResponseWriter, r *http.Request, storagePath string) { reqID := uuid.New() log.Printf("%s | %s %s\n", reqID.String(), r.Method, r.URL.EscapedPath()) path := strings.Split(r.URL.Path, "/")[1:] if len(path) != 1 { log.Printf("%s | 404", reqID.String()) w.WriteHeader(http.StatusNotFound) return } key := path[0] if key == "" { handleRoot(r.Method, reqID.String(), w) return } if !filepath.IsLocal(key) { log.Printf("%s | 400", reqID) w.WriteHeader(http.StatusBadRequest) return } switch r.Method { case "GET": fallthrough case "": status := getFile(storagePath, key, reqID.String(), w) log.Printf("%s | %d\n", reqID.String(), status) w.WriteHeader(status) return case "PUT": status := putFile(storagePath, key, reqID.String(), w, r.Body) log.Printf("%s | %d\n", reqID.String(), status) w.WriteHeader(status) return default: log.Printf("%s | 405", reqID) w.WriteHeader(http.StatusMethodNotAllowed) return } } func main() { storagePath := flag.String("s", "/var/lib/cranberry", "storage path") port := flag.Int("p", 8080, "port") host := flag.String("h", "", "host") flag.Parse() http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { handler(w, r, *storagePath) }) address := fmt.Sprintf("%s:%d", *host, *port) err := http.ListenAndServe(address, nil) if err != nil { fmt.Printf("while listening: %v", err) } } |