MCPcopy Create free account
hub / github.com/quay/clair / DiscoveryHandler

Function DiscoveryHandler

httptransport/discoveryhandler.go:47–116  ·  view source on GitHub ↗

DiscoveryHandler serves the embedded OpenAPI spec.

(_ context.Context, prefix string, topt otelhttp.Option)

Source from the content-addressed store, hash-verified

45
46// DiscoveryHandler serves the embedded OpenAPI spec.
47func DiscoveryHandler(_ context.Context, prefix string, topt otelhttp.Option) http.Handler {
48 allow := []string{
49 `application/openapi+json`, `application/openapi+yaml`, // New types: https://datatracker.ietf.org/doc/draft-ietf-httpapi-rest-api-mediatypes/
50 `application/json`, `application/yaml`, // Format types.
51 `application/vnd.oai.openapi+json`, `application/vnd.oai.openapi+yaml`, // Older vendor-tree types.
52 }
53 // These functions are written back-to-front.
54 var inner http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
55 ctx := r.Context()
56 if r.Method != http.MethodGet {
57 apiError(ctx, w, http.StatusMethodNotAllowed, "endpoint only allows GET")
58 }
59 switch err := pickContentType(w, r, allow); {
60 case errors.Is(err, nil):
61 case errors.Is(err, ErrMediaType):
62 apiError(ctx, w, http.StatusUnsupportedMediaType, "unable to negotiate common media type for %v", allow)
63 default:
64 apiError(ctx, w, http.StatusInternalServerError, "unexpected error: %v", err)
65 }
66 h := w.Header()
67 kind := h.Get(`Content-Type`)
68 var src *bytes.Reader
69 switch kind[len(kind)-4:] {
70 case "json":
71 src = bytes.NewReader(compactOpenapiJSON())
72 case "yaml":
73 src = bytes.NewReader(openapiYAML)
74 default:
75 apiError(ctx, w, http.StatusInternalServerError, "unexpected error: unknown content-type kind: %q", kind)
76 }
77 h.Set("Etag", openapiEtag)
78 var err error
79 defer writerError(w, &err)()
80 _, err = io.Copy(w, src)
81 })
82 inner = otelhttp.NewHandler(
83 compress.Handler(discoverywrapper.wrap(prefix, inner)),
84 "discovery",
85 otelhttp.WithMessageEvents(otelhttp.ReadEvents, otelhttp.WriteEvents),
86 topt,
87 )
88 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
89 start := time.Now()
90 r = withRequestID(r)
91 ctx := r.Context()
92 var status int
93 var length int64
94 w = httputil.ResponseRecorder(&status, &length, w)
95 defer func() {
96 switch err := http.NewResponseController(w).Flush(); {
97 case errors.Is(err, nil):
98 case errors.Is(err, http.ErrNotSupported):
99 // Skip
100 default:
101 zlog.Warn(ctx).
102 Err(err).
103 Msg("unable to flush http response")
104 }

Callers 2

NewFunction · 0.85
TestDiscoveryFunction · 0.85

Calls 13

HandlerFunction · 0.92
ResponseRecorderFunction · 0.92
apiErrorFunction · 0.85
pickContentTypeFunction · 0.85
writerErrorFunction · 0.85
withRequestIDFunction · 0.85
CopyMethod · 0.80
wrapMethod · 0.80
FlushMethod · 0.80
ErrMethod · 0.80
InfoMethod · 0.80
SetMethod · 0.45

Tested by 1

TestDiscoveryFunction · 0.68