55#include < ydb/core/grpc_services/base/base.h>
66#include < ydb/core/base/ticket_parser.h>
77
8+ #include < library/cpp/json/json_writer.h>
89#include < library/cpp/lwtrace/all.h>
910#include < library/cpp/lwtrace/mon/mon_lwtrace.h>
1011#include < ydb/library/actors/core/probes.h>
@@ -145,6 +146,11 @@ class THttpMonRequest : public NMonitoring::IMonHttpRequest {
145146 return {};
146147 }
147148
149+ bool AcceptsJsonResponse () {
150+ TStringBuf acceptHeader = GetHeader (" Accept" );
151+ return acceptHeader.find (TStringBuf (" application/json" )) != TStringBuf::npos;
152+ }
153+
148154 virtual TStringBuf GetCookie (TStringBuf name) const override {
149155 NHttp::TCookies cookies (GetHeader (" Cookie" ));
150156 return cookies.Get (name);
@@ -251,7 +257,7 @@ class THttpMonLegacyActorRequest : public TActorBootstrapped<THttpMonLegacyActor
251257 TString YdbToHttpError (Ydb::StatusIds::StatusCode status) {
252258 switch (status) {
253259 case Ydb::StatusIds::UNAUTHORIZED:
254- return " 401 Unauthorized " ;
260+ return " 403 Forbidden " ;
255261 case Ydb::StatusIds::INTERNAL_ERROR:
256262 return " 500 Internal Server Error" ;
257263 case Ydb::StatusIds::UNAVAILABLE:
@@ -268,26 +274,45 @@ class THttpMonLegacyActorRequest : public TActorBootstrapped<THttpMonLegacyActor
268274 }
269275
270276 void ReplyErrorAndPassAway (const NKikimr::NGRpcService::TEvRequestAuthAndCheckResult& result) {
277+ ReplyErrorAndPassAway (result.Status , result.Issues , true );
278+ }
279+
280+ void ReplyErrorAndPassAway (Ydb::StatusIds::StatusCode status, const NYql::TIssues& issues, bool addAccessControlHeaders) {
271281 NHttp::THttpIncomingRequestPtr request = Event->Get ()->Request ;
272- NHttp::THeaders headers (request->Headers );
273282 TStringBuilder response;
274283 TStringBuilder body;
275- const TString httpError = YdbToHttpError (result.Status );
276- body << " <html><body><h1>" << httpError << " </h1>" ;
277- if (result.Issues ) {
278- body << " <p>" << result.Issues .ToString () << " </p>" ;
279- }
280- body << " </body></html>" ;
281- TString origin = TString (headers[" Origin" ]);
282- if (origin.empty ()) {
283- origin = " *" ;
284+ TStringBuf contentType;
285+ const TString httpError = YdbToHttpError (status);
286+
287+ if (Container.AcceptsJsonResponse ()) {
288+ contentType = " application/json" ;
289+ NJson::TJsonValue json;
290+ TString message;
291+ MakeJsonErrorReply (json, message, issues, NYdb::EStatus (status));
292+ NJson::WriteJson (&body.Out , &json);
293+ } else {
294+ contentType = " text/html" ;
295+ body << " <html><body><h1>" << httpError << " </h1>" ;
296+ if (issues) {
297+ body << " <p>" << issues.ToString () << " </p>" ;
298+ }
299+ body << " </body></html>" ;
284300 }
301+
285302 response << " HTTP/1.1 " << httpError << " \r\n " ;
286- response << " Access-Control-Allow-Origin: " << origin << " \r\n " ;
287- response << " Access-Control-Allow-Credentials: true\r\n " ;
288- response << " Access-Control-Allow-Headers: Content-Type,Authorization,Origin,Accept\r\n " ;
289- response << " Access-Control-Allow-Methods: OPTIONS, GET, POST, PUT, DELETE\r\n " ;
290- response << " Content-Type: text/html\r\n " ;
303+ if (addAccessControlHeaders) {
304+ NHttp::THeaders headers (request->Headers );
305+ TString origin = TString (headers[" Origin" ]);
306+ if (origin.empty ()) {
307+ origin = " *" ;
308+ }
309+ response << " Access-Control-Allow-Origin: " << origin << " \r\n " ;
310+ response << " Access-Control-Allow-Credentials: true\r\n " ;
311+ response << " Access-Control-Allow-Headers: Content-Type,Authorization,Origin,Accept\r\n " ;
312+ response << " Access-Control-Allow-Methods: OPTIONS, GET, POST, PUT, DELETE\r\n " ;
313+ }
314+
315+ response << " Content-Type: " << contentType << " \r\n " ;
291316 response << " Content-Length: " << body.Size () << " \r\n " ;
292317 response << " \r\n " ;
293318 response << body;
@@ -296,21 +321,9 @@ class THttpMonLegacyActorRequest : public TActorBootstrapped<THttpMonLegacyActor
296321 }
297322
298323 void ReplyForbiddenAndPassAway (const TString& error = {}) {
299- NHttp::THttpIncomingRequestPtr request = Event->Get ()->Request ;
300- TStringBuilder response;
301- TStringBuilder body;
302- body << " <html><body><h1>403 Forbidden</h1>" ;
303- if (!error.empty ()) {
304- body << " <p>" << error << " </p>" ;
305- }
306- body << " </body></html>" ;
307- response << " HTTP/1.1 403 Forbidden\r\n " ;
308- response << " Content-Type: text/html\r\n " ;
309- response << " Content-Length: " << body.Size () << " \r\n " ;
310- response << " \r\n " ;
311- response << body;
312- ReplyWith (request->CreateResponseString (response));
313- PassAway ();
324+ NYql::TIssues issues;
325+ issues.AddIssue (error);
326+ ReplyErrorAndPassAway (Ydb::StatusIds::UNAUTHORIZED, issues, false );
314327 }
315328
316329 void SendRequest (const NKikimr::NGRpcService::TEvRequestAuthAndCheckResult* result = nullptr ) {
0 commit comments