package app import ( "errors" "fmt" "io" "net/http" "os" "path/filepath" "strings" ) func (s *Server) saveUpload(r *http.Request, field string) (string, bool, error) { if !strings.HasPrefix(r.Header.Get("Content-Type"), "multipart/form-data") { return "", false, nil } file, header, err := r.FormFile(field) if errors.Is(err, http.ErrMissingFile) { return "", false, nil } if err != nil { return "", false, err } defer file.Close() ext := strings.ToLower(filepath.Ext(header.Filename)) switch ext { case ".jpg", ".jpeg", ".png", ".webp", ".gif": default: return "", false, fmt.Errorf("unsupported image type") } name, err := randomToken() if err != nil { return "", false, err } filename := name + ext target := filepath.Join(s.cfg.UploadDir, filename) out, err := os.OpenFile(target, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o644) if err != nil { return "", false, err } defer out.Close() written, err := io.Copy(out, io.LimitReader(file, maxUploadBytes+1)) if err != nil { return "", false, err } if written > maxUploadBytes { _ = out.Close() _ = os.Remove(target) return "", false, fmt.Errorf("is too large") } return "/uploads/" + filename, true, nil } func parseAdminForm(w http.ResponseWriter, r *http.Request, maxBytes int64) error { r.Body = http.MaxBytesReader(w, r.Body, maxBytes) if strings.HasPrefix(r.Header.Get("Content-Type"), "multipart/form-data") { return r.ParseMultipartForm(maxBytes) } return r.ParseForm() }