forked from quay/clair
/
updateoperationhandler.go
139 lines (123 loc) · 3.64 KB
/
updateoperationhandler.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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package httptransport
import (
"fmt"
"net/http"
"path/filepath"
"strconv"
"github.com/google/uuid"
"github.com/quay/claircore/libvuln/driver"
je "github.com/quay/claircore/pkg/jsonerr"
"github.com/quay/zlog"
"go.opentelemetry.io/otel/baggage"
"go.opentelemetry.io/otel/label"
"github.com/quay/clair/v4/internal/codec"
"github.com/quay/clair/v4/matcher"
)
var _ http.Handler = (*UOHandler)(nil)
// UOHandler implements http.Handler and provides http.HandlerFunc(s)
// for GET and DELETE operations.
type UOHandler struct {
serv matcher.Differ
}
// UpdateOperationHandler creates a new UOHandler
func UpdateOperationHandler(serv matcher.Differ) *UOHandler {
return &UOHandler{
serv: serv,
}
}
// ServeHTTP provides GET and DELETE operations for UpdateOperation models.
//
// Implements http.Handler interface and may also be used as a http.HandlerFunc
func (h *UOHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
h.Get(w, r)
case http.MethodDelete:
h.Delete(w, r)
default:
resp := &je.Response{
Code: "method-not-allowed",
Message: "endpoint only allows POST",
}
je.Error(w, resp, http.StatusMethodNotAllowed)
}
}
// Get retrieves UpdateOperation models.
//
// Supports conditional requests by providing the newest UpdateOperation as
// an etag.
// Clients may provide an 'If-None-Match' header with the etag value to receive
// a StatusNotModified when no new UpdateOperations have been created.
func (h *UOHandler) Get(w http.ResponseWriter, r *http.Request) {
ctx := baggage.ContextWithValues(r.Context(),
label.String("component", "httptransport/UOHandler.Get"),
)
kind := driver.VulnerabilityKind
switch k := r.URL.Query().Get("kind"); k {
case "enrichment":
kind = driver.EnrichmentKind
case "", "vulnerability":
// Leave as default
default:
je.Error(w, &je.Response{
Code: "bad-request",
Message: fmt.Sprintf("unknown kind: %q", k),
}, http.StatusBadRequest)
return
}
// handle conditional request. this is an optimization
if ref, err := h.serv.LatestUpdateOperation(ctx, kind); err == nil {
validator := `"` + ref.String() + `"`
if unmodified(r, validator) {
w.WriteHeader(http.StatusNotModified)
return
}
w.Header().Set("etag", validator)
}
latest := r.URL.Query().Get("latest")
var uos map[string][]driver.UpdateOperation
var err error
if b, _ := strconv.ParseBool(latest); b {
uos, err = h.serv.LatestUpdateOperations(ctx, kind)
} else {
uos, err = h.serv.UpdateOperations(ctx, kind)
}
if err != nil {
resp := &je.Response{
Code: "internal server error",
Message: fmt.Sprintf("could not get update operations: %v", err),
}
je.Error(w, resp, http.StatusInternalServerError)
return
}
defer writerError(w, &err)()
enc := codec.GetEncoder(w)
defer codec.PutEncoder(enc)
err = enc.Encode(&uos)
}
// Delete removes an UpdateOperation models from the system.
func (h *UOHandler) Delete(w http.ResponseWriter, r *http.Request) {
ctx := baggage.ContextWithValues(r.Context(),
label.String("component", "httptransport/UOHandler.Delete"),
)
path := r.URL.Path
id := filepath.Base(path)
uuid, err := uuid.Parse(id)
if err != nil {
resp := &je.Response{
Code: "bad-request",
Message: fmt.Sprintf("could not deserialize manifest: %v", err),
}
zlog.Warn(ctx).Err(err).Msg("could not deserialize manifest")
je.Error(w, resp, http.StatusBadRequest)
return
}
_, err = h.serv.DeleteUpdateOperations(ctx, uuid)
if err != nil {
resp := &je.Response{
Code: "internal server error",
Message: fmt.Sprintf("could not get update operations: %v", err),
}
je.Error(w, resp, http.StatusInternalServerError)
}
}