@@ -33,6 +33,7 @@ import (
3333	jsoniter "github.com/json-iterator/go" 
3434	"github.com/munnerz/goautoneg" 
3535	"gopkg.in/yaml.v2" 
36+ 	klog "k8s.io/klog/v2" 
3637	"k8s.io/kube-openapi/pkg/builder" 
3738	"k8s.io/kube-openapi/pkg/common" 
3839	"k8s.io/kube-openapi/pkg/validation/spec" 
@@ -55,13 +56,26 @@ type OpenAPIService struct {
5556
5657	lastModified  time.Time 
5758
58- 	specBytes  []byte 
59- 	specPb     []byte 
60- 	specPbGz   []byte 
59+ 	jsonCache   cache 
60+ 	protoCache  cache 
61+ }
62+ 
63+ type  cache  struct  {
64+ 	BuildCache  func () ([]byte , error )
65+ 	once        sync.Once 
66+ 	bytes       []byte 
67+ 	etag        string 
68+ 	err         error 
69+ }
6170
62- 	specBytesETag  string 
63- 	specPbETag     string 
64- 	specPbGzETag   string 
71+ func  (c  * cache ) Get () ([]byte , string , error ) {
72+ 	c .once .Do (func () {
73+ 		c .bytes , c .err  =  c .BuildCache ()
74+ 		if  c .err  !=  nil  {
75+ 			c .etag  =  computeETag (c .bytes )
76+ 		}
77+ 	})
78+ 	return  c .bytes , c .etag , c .err 
6579}
6680
6781func  init () {
@@ -83,50 +97,44 @@ func NewOpenAPIService(spec *spec.Swagger) (*OpenAPIService, error) {
8397	return  o , nil 
8498}
8599
86- func  (o  * OpenAPIService ) getSwaggerBytes () ([]byte , string , time.Time ) {
87- 	o .rwMutex .RLock ()
88- 	defer  o .rwMutex .RUnlock ()
89- 	return  o .specBytes , o .specBytesETag , o .lastModified 
90- }
91- 
92- func  (o  * OpenAPIService ) getSwaggerPbBytes () ([]byte , string , time.Time ) {
100+ func  (o  * OpenAPIService ) getSwaggerBytes () ([]byte , string , time.Time , error ) {
93101	o .rwMutex .RLock ()
94102	defer  o .rwMutex .RUnlock ()
95- 	return  o .specPb , o .specPbETag , o .lastModified 
103+ 	specBytes , etag , err  :=  o .jsonCache .Get ()
104+ 	if  err  !=  nil  {
105+ 		return  nil , "" , time.Time {}, err 
106+ 	}
107+ 	return  specBytes , etag , o .lastModified , nil 
96108}
97109
98- func  (o  * OpenAPIService ) getSwaggerPbGzBytes () ([]byte , string , time.Time ) {
110+ func  (o  * OpenAPIService ) getSwaggerPbBytes () ([]byte , string , time.Time ,  error ) {
99111	o .rwMutex .RLock ()
100112	defer  o .rwMutex .RUnlock ()
101- 	return  o .specPbGz , o .specPbGzETag , o .lastModified 
113+ 	specPb , etag , err  :=  o .protoCache .Get ()
114+ 	if  err  !=  nil  {
115+ 		return  nil , "" , time.Time {}, err 
116+ 	}
117+ 	return  specPb , etag , o .lastModified , nil 
102118}
103119
104120func  (o  * OpenAPIService ) UpdateSpec (openapiSpec  * spec.Swagger ) (err  error ) {
105- 	specBytes , err  :=  jsoniter .ConfigCompatibleWithStandardLibrary .Marshal (openapiSpec )
106- 	if  err  !=  nil  {
107- 		return  err 
121+ 	o .rwMutex .Lock ()
122+ 	defer  o .rwMutex .Unlock ()
123+ 	o .jsonCache  =  cache {
124+ 		BuildCache : func () ([]byte , error ) {
125+ 			return  jsoniter .ConfigCompatibleWithStandardLibrary .Marshal (openapiSpec )
126+ 		},
108127	}
109- 	specPb , err  :=  ToProtoBinary (specBytes )
110- 	if  err  !=  nil  {
111- 		return  err 
128+ 	o .protoCache  =  cache {
129+ 		BuildCache : func () ([]byte , error ) {
130+ 			json , _ , err  :=  o .jsonCache .Get ()
131+ 			if  err  !=  nil  {
132+ 				return  nil , err 
133+ 			}
134+ 			return  ToProtoBinary (json )
135+ 		},
112136	}
113- 	specPbGz  :=  toGzip (specPb )
114- 
115- 	specBytesETag  :=  computeETag (specBytes )
116- 	specPbETag  :=  computeETag (specPb )
117- 	specPbGzETag  :=  computeETag (specPbGz )
118- 
119137	lastModified  :=  time .Now ()
120- 
121- 	o .rwMutex .Lock ()
122- 	defer  o .rwMutex .Unlock ()
123- 
124- 	o .specBytes  =  specBytes 
125- 	o .specPb  =  specPb 
126- 	o .specPbGz  =  specPbGz 
127- 	o .specBytesETag  =  specBytesETag 
128- 	o .specPbETag  =  specPbETag 
129- 	o .specPbGzETag  =  specPbGzETag 
130138	o .lastModified  =  lastModified 
131139
132140	return  nil 
@@ -206,7 +214,7 @@ func (o *OpenAPIService) RegisterOpenAPIVersionedService(servePath string, handl
206214	accepted  :=  []struct  {
207215		Type            string 
208216		SubType         string 
209- 		GetDataAndETag  func () ([]byte , string , time.Time )
217+ 		GetDataAndETag  func () ([]byte , string , time.Time ,  error )
210218	}{
211219		{"application" , "json" , o .getSwaggerBytes },
212220		{
"application" , 
"[email protected] +protobuf" , 
o .
getSwaggerPbBytes },
@@ -230,7 +238,12 @@ func (o *OpenAPIService) RegisterOpenAPIVersionedService(servePath string, handl
230238					}
231239
232240					// serve the first matching media type in the sorted clause list 
233- 					data , etag , lastModified  :=  accepts .GetDataAndETag ()
241+ 					data , etag , lastModified , err  :=  accepts .GetDataAndETag ()
242+ 					if  err  !=  nil  {
243+ 						klog .Errorf ("Error in OpenAPI handler: %s" , err )
244+ 						w .WriteHeader (http .StatusInternalServerError )
245+ 						return 
246+ 					}
234247					w .Header ().Set ("Etag" , etag )
235248					// ServeContent will take care of caching using eTag. 
236249					http .ServeContent (w , r , servePath , lastModified , bytes .NewReader (data ))
0 commit comments