@@ -146,6 +146,25 @@ func (rp *reverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
146146 }
147147
148148 if shouldReturnFromCache {
149+ // if cache shared between all users
150+ // try to check if cached query is allowed for current user
151+ if s .user .cache != nil && s .user .cache .SharedWithAllUsers && s .user .cache .CheckGrantsForSharedCache {
152+ checkReq , checkQuery , _ := s .createCheckGrantsRequest (req )
153+
154+ srwCheck := & checkGrantsResponseWriter {
155+ ResponseWriter : srw .ResponseWriter ,
156+ }
157+
158+ rp .proxyRequest (s , srwCheck , srw , checkReq )
159+
160+ if srwCheck .statusCode == http .StatusOK {
161+ log .Debugf ("%s: check grants for shared cached query request success; query: %q; Method: %s; URL: %q" , s , checkQuery , checkReq .Method , checkReq .URL .String ())
162+ } else {
163+ log .Debugf ("%s: check grants for shared cached query request failure: non-200 status code %d; query: %q; Method: %s; URL: %q" , s , srwCheck .statusCode , checkQuery , checkReq .Method , checkReq .URL .String ())
164+ return
165+ }
166+ }
167+
149168 rp .serveFromCache (s , srw , req , origParams , q )
150169 } else {
151170 rp .proxyRequest (s , srw , srw , req )
@@ -925,3 +944,45 @@ func (rp *reverseProxy) getScope(req *http.Request) (*scope, int, error) {
925944 s .requestPacketSize = len (q )
926945 return s , 0 , nil
927946}
947+
948+ // create a new request based on proxied one
949+ // with query wrapped to fetch result types like:
950+ // 'DESC ({original_query})'
951+ // along with query parsed and analyzed for return types (which is fast)
952+ // ClickHouse check permissions to execute this query for the user
953+ func (s * scope ) createCheckGrantsRequest (originalReq * http.Request ) (* http.Request , string , error ) {
954+ originalQuery := originalReq .URL .Query ().Get ("query" )
955+ checkQuery := fmt .Sprintf ("DESC (%s);" , strings .TrimRight (originalQuery , ";" ))
956+
957+ // Создаем новый URL, копируя оригинальный
958+ newURL := * originalReq .URL
959+
960+ // Парсим Query параметры
961+ queryParams , err := url .ParseQuery (newURL .RawQuery )
962+ if err != nil {
963+ return nil , checkQuery , err
964+ }
965+
966+ // Изменяем или добавляем параметр "test"
967+ queryParams .Set ("query" , checkQuery )
968+
969+ // Обновляем RawQuery в новом URL
970+ newURL .RawQuery = queryParams .Encode ()
971+
972+ // Создаем новый запрос, используя оригинальный в качестве шаблона
973+ req := & http.Request {
974+ Method : originalReq .Method ,
975+ URL : & newURL ,
976+ Proto : originalReq .Proto ,
977+ ProtoMajor : originalReq .ProtoMajor ,
978+ ProtoMinor : originalReq .ProtoMinor ,
979+ Header : originalReq .Header .Clone (),
980+ Body : originalReq .Body ,
981+ Host : originalReq .Host ,
982+ ContentLength : originalReq .ContentLength ,
983+ Close : originalReq .Close ,
984+ TLS : originalReq .TLS ,
985+ }
986+
987+ return req , checkQuery , nil
988+ }
0 commit comments