@@ -18,6 +18,7 @@ package handler3
1818
1919import (
2020 "bytes"
21+ "crypto/sha512"
2122 "encoding/json"
2223 "fmt"
2324 "mime"
@@ -33,7 +34,6 @@ import (
3334 "github.com/golang/protobuf/proto"
3435 openapi_v3 "github.com/googleapis/gnostic/openapiv3"
3536 "github.com/munnerz/goautoneg"
36- klog "k8s.io/klog/v2"
3737 "k8s.io/kube-openapi/pkg/common"
3838 "k8s.io/kube-openapi/pkg/internal/handler"
3939 "k8s.io/kube-openapi/pkg/spec3"
@@ -52,13 +52,6 @@ const (
5252 subTypeJSON = "json"
5353)
5454
55- func computeETag (data []byte ) string {
56- if data == nil {
57- return ""
58- }
59- return fmt .Sprintf ("%X" , sha512 .Sum512 (data ))
60- }
61-
6255// OpenAPIV3Discovery is the format of the Discovery document for OpenAPI V3
6356// It maps Discovery paths to their corresponding URLs with a hash parameter included
6457type OpenAPIV3Discovery struct {
@@ -87,6 +80,7 @@ type OpenAPIV3Group struct {
8780
8881 pbCache handler.HandlerCache
8982 jsonCache handler.HandlerCache
83+ etagCache handler.HandlerCache
9084}
9185
9286func init () {
@@ -95,22 +89,29 @@ func init() {
9589 mime .AddExtensionType (".gz" , mimePbGz )
9690}
9791
98- // NewOpenAPIService builds an OpenAPIService starting with the given spec.
99- func NewOpenAPIService ( spec * spec. Swagger ) ( * OpenAPIService , error ) {
100- o := & OpenAPIService {}
101- o . v3Schema = make ( map [ string ] * OpenAPIV3Group )
102- return o , nil
92+ func computeETag ( data [] byte ) string {
93+ if data == nil {
94+ return ""
95+ }
96+ return fmt . Sprintf ( "%X" , sha512 . Sum512 ( data ))
10397}
10498
105- func constructURL (r * http. Request , gvString , etag string ) ( string , error ) {
99+ func constructURL (gvString , etag string ) string {
106100 u := url.URL {Path : path .Join ("/openapi/v3" , gvString )}
107101 query := url.Values {}
108102 query .Set ("hash" , etag )
109103 u .RawQuery = query .Encode ()
110- return u .String (), nil
104+ return u .String ()
111105}
112106
113- func (o * OpenAPIService ) getGroupBytes (r * http.Request ) ([]byte , error ) {
107+ // NewOpenAPIService builds an OpenAPIService starting with the given spec.
108+ func NewOpenAPIService (spec * spec.Swagger ) (* OpenAPIService , error ) {
109+ o := & OpenAPIService {}
110+ o .v3Schema = make (map [string ]* OpenAPIV3Group )
111+ return o , nil
112+ }
113+
114+ func (o * OpenAPIService ) getGroupBytes () ([]byte , error ) {
114115 o .rwMutex .RLock ()
115116 defer o .rwMutex .RUnlock ()
116117 keys := make ([]string , len (o .v3Schema ))
@@ -123,15 +124,13 @@ func (o *OpenAPIService) getGroupBytes(r *http.Request) ([]byte, error) {
123124 sort .Strings (keys )
124125 discovery := & OpenAPIV3Discovery {Paths : make (map [string ]OpenAPIV3DiscoveryGroupVersion )}
125126 for gvString , groupVersion := range o .v3Schema {
126- _ , etag , err := groupVersion .jsonCache .Get ()
127+ etagBytes , err := groupVersion .etagCache .Get ()
127128 if err != nil {
128129 return nil , err
129130 }
130- u , err := constructURL (r , gvString , etag )
131- if err != nil {
132- return nil , err
131+ discovery .Paths [gvString ] = OpenAPIV3DiscoveryGroupVersion {
132+ URL : constructURL (gvString , string (etagBytes )),
133133 }
134- discovery .Paths [gvString ] = OpenAPIV3DiscoveryGroupVersion {URL : u }
135134 }
136135 j , err := json .Marshal (discovery )
137136 if err != nil {
@@ -148,15 +147,19 @@ func (o *OpenAPIService) getSingleGroupBytes(getType string, group string) ([]by
148147 return nil , "" , time .Now (), fmt .Errorf ("Cannot find CRD group %s" , group )
149148 }
150149 if getType == subTypeJSON {
151- specBytes , etag , err := v .jsonCache .Get ()
152- return specBytes , etag , v .lastModified , err
150+ specBytes , err := v .jsonCache .Get ()
151+ if err != nil {
152+ return nil , "" , v .lastModified , err
153+ }
154+ etagBytes , err := v .etagCache .Get ()
155+ return specBytes , string (etagBytes ), v .lastModified , err
153156 } else if getType == subTypeProtobuf {
154- _ , etag , err := v .jsonCache .Get ()
157+ specPb , err := v .pbCache .Get ()
155158 if err != nil {
156159 return nil , "" , v .lastModified , err
157160 }
158- specPb , _ , err := v .pbCache .Get ()
159- return specPb , etag , v .lastModified , err
161+ etagBytes , err := v .etagCache .Get ()
162+ return specPb , string ( etagBytes ) , v .lastModified , err
160163 }
161164 return nil , "" , time .Now (), fmt .Errorf ("Invalid accept clause %s" , getType )
162165}
@@ -186,7 +189,7 @@ func ToV3ProtoBinary(json []byte) ([]byte, error) {
186189}
187190
188191func (o * OpenAPIService ) HandleDiscovery (w http.ResponseWriter , r * http.Request ) {
189- data , _ := o .getGroupBytes (r )
192+ data , _ := o .getGroupBytes ()
190193 http .ServeContent (w , r , "/openapi/v3" , time .Now (), bytes .NewReader (data ))
191194}
192195
@@ -249,11 +252,7 @@ func (o *OpenAPIService) HandleGroupVersion(w http.ResponseWriter, r *http.Reque
249252 w .Header ().Set ("Etag" , strconv .Quote (etag ))
250253
251254 if CacheBustingShouldRedirect (r , etag ) {
252- u , err := constructURL (r , group , etag )
253- if err != nil {
254- klog .Errorf ("Error parsing URL %s, %v" , r .URL .String (), err )
255- return
256- }
255+ u := constructURL (group , etag )
257256 http .Redirect (w , r , u , 301 )
258257 return
259258 }
@@ -276,24 +275,22 @@ func (o *OpenAPIV3Group) UpdateSpec(openapi *spec3.OpenAPI) (err error) {
276275 o .rwMutex .Lock ()
277276 defer o .rwMutex .Unlock ()
278277
279- o .pbCache = o .pbCache .New (func () ([]byte , string , error ) {
280- json , etag , err := o .jsonCache .Get ()
281- if err != nil {
282- return nil , "" , err
283- }
284- pb , err := ToV3ProtoBinary (json )
278+ o .pbCache = o .pbCache .New (func () ([]byte , error ) {
279+ json , err := o .jsonCache .Get ()
285280 if err != nil {
286- return nil , "" , err
281+ return nil , err
287282 }
288- return pb , etag , nil
283+ return ToV3ProtoBinary ( json )
289284 })
290-
291- o .jsonCache = o .jsonCache .New (func () ([]byte , string , error ) {
292- specBytes , err := json .Marshal (openapi )
285+ o .jsonCache = o .jsonCache .New (func () ([]byte , error ) {
286+ return json .Marshal (openapi )
287+ })
288+ o .etagCache = o .etagCache .New (func () ([]byte , error ) {
289+ json , err := o .jsonCache .Get ()
293290 if err != nil {
294- return nil , "" , err
291+ return nil , err
295292 }
296- return specBytes , "" , nil
293+ return [] byte ( computeETag ( json )) , nil
297294 })
298295 o .lastModified = time .Now ()
299296 return nil
0 commit comments