1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
16
17 package handlers
18
19 import (
20 "fmt"
21 "log"
22 "net/http"
23
24 "perkeep.org/internal/httputil"
25 "perkeep.org/pkg/blob"
26 "perkeep.org/pkg/blobserver"
27 )
28
29 const maxRemovesPerRequest = 1000
30
31 func CreateRemoveHandler(storage blobserver.Storage) http.Handler {
32 return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
33 handleRemove(rw, req, storage)
34 })
35 }
36
37
38 type RemoveResponse struct {
39 Removed []blob.Ref `json:"removed"`
40 Error string `json:"error"`
41 }
42
43 func handleRemove(w http.ResponseWriter, r *http.Request, storage blobserver.Storage) {
44 ctx := r.Context()
45 if r.Method != "POST" {
46 log.Fatalf("Invalid method; handlers misconfigured")
47 }
48
49 configer, ok := storage.(blobserver.Configer)
50 if !ok {
51 msg := fmt.Sprintf("remove handler's blobserver.Storage isn't a blobserver.Configer, but a %T; can't remove", storage)
52 log.Printf("blobserver/handlers: %v", msg)
53 httputil.ReturnJSONCode(w, http.StatusForbidden, RemoveResponse{Error: msg})
54 return
55 }
56 if !configer.Config().Deletable {
57 msg := fmt.Sprintf("storage %T does not permit deletes", storage)
58 log.Printf("blobserver/handlers: %v", msg)
59 httputil.ReturnJSONCode(w, http.StatusForbidden, RemoveResponse{Error: msg})
60 return
61 }
62
63 n := 0
64 toRemove := make([]blob.Ref, 0)
65 for {
66 n++
67 if n > maxRemovesPerRequest {
68 httputil.BadRequestError(w,
69 fmt.Sprintf("Too many removes in this request; max is %d", maxRemovesPerRequest))
70 return
71 }
72 key := fmt.Sprintf("blob%v", n)
73 value := r.FormValue(key)
74 if value == "" {
75 break
76 }
77 ref, ok := blob.Parse(value)
78 if !ok {
79 httputil.BadRequestError(w, "Bogus blobref for key "+key)
80 return
81 }
82 toRemove = append(toRemove, ref)
83 }
84
85 err := storage.RemoveBlobs(ctx, toRemove)
86 if err != nil {
87 w.WriteHeader(http.StatusInternalServerError)
88 log.Printf("Server error during remove: %v", err)
89 fmt.Fprintf(w, "Server error")
90 return
91 }
92
93 httputil.ReturnJSON(w, &RemoveResponse{Removed: toRemove})
94 }