5
5
#include < ydb/core/grpc_services/base/base.h>
6
6
#include < ydb/core/base/ticket_parser.h>
7
7
8
+ #include < library/cpp/json/json_writer.h>
8
9
#include < library/cpp/lwtrace/all.h>
9
10
#include < library/cpp/lwtrace/mon/mon_lwtrace.h>
10
11
#include < ydb/library/actors/core/probes.h>
@@ -145,6 +146,11 @@ class THttpMonRequest : public NMonitoring::IMonHttpRequest {
145
146
return {};
146
147
}
147
148
149
+ bool AcceptsJsonResponse () {
150
+ TStringBuf acceptHeader = GetHeader (" Accept" );
151
+ return acceptHeader.find (TStringBuf (" application/json" )) != TStringBuf::npos;
152
+ }
153
+
148
154
virtual TStringBuf GetCookie (TStringBuf name) const override {
149
155
NHttp::TCookies cookies (GetHeader (" Cookie" ));
150
156
return cookies.Get (name);
@@ -248,10 +254,15 @@ class THttpMonLegacyActorRequest : public TActorBootstrapped<THttpMonLegacyActor
248
254
PassAway ();
249
255
}
250
256
257
+ bool CredentialsProvided () {
258
+ return Container.GetCookie (" ydb_session_id" ) || Container.GetHeader (" Authorization" );
259
+ }
260
+
251
261
TString YdbToHttpError (Ydb::StatusIds::StatusCode status) {
252
262
switch (status) {
253
263
case Ydb::StatusIds::UNAUTHORIZED:
254
- return " 401 Unauthorized" ;
264
+ // YDB status UNAUTHORIZED is used for both access denied case and if no credentials were provided.
265
+ return CredentialsProvided () ? " 403 Forbidden" : " 401 Unauthorized" ;
255
266
case Ydb::StatusIds::INTERNAL_ERROR:
256
267
return " 500 Internal Server Error" ;
257
268
case Ydb::StatusIds::UNAVAILABLE:
@@ -268,26 +279,45 @@ class THttpMonLegacyActorRequest : public TActorBootstrapped<THttpMonLegacyActor
268
279
}
269
280
270
281
void ReplyErrorAndPassAway (const NKikimr::NGRpcService::TEvRequestAuthAndCheckResult& result) {
282
+ ReplyErrorAndPassAway (result.Status , result.Issues , true );
283
+ }
284
+
285
+ void ReplyErrorAndPassAway (Ydb::StatusIds::StatusCode status, const NYql::TIssues& issues, bool addAccessControlHeaders) {
271
286
NHttp::THttpIncomingRequestPtr request = Event->Get ()->Request ;
272
- NHttp::THeaders headers (request->Headers );
273
287
TStringBuilder response;
274
288
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 = " *" ;
289
+ TStringBuf contentType;
290
+ const TString httpError = YdbToHttpError (status);
291
+
292
+ if (Container.AcceptsJsonResponse ()) {
293
+ contentType = " application/json" ;
294
+ NJson::TJsonValue json;
295
+ TString message;
296
+ MakeJsonErrorReply (json, message, issues, NYdb::EStatus (status));
297
+ NJson::WriteJson (&body.Out , &json);
298
+ } else {
299
+ contentType = " text/html" ;
300
+ body << " <html><body><h1>" << httpError << " </h1>" ;
301
+ if (issues) {
302
+ body << " <p>" << issues.ToString () << " </p>" ;
303
+ }
304
+ body << " </body></html>" ;
284
305
}
306
+
285
307
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 " ;
308
+ if (addAccessControlHeaders) {
309
+ NHttp::THeaders headers (request->Headers );
310
+ TString origin = TString (headers[" Origin" ]);
311
+ if (origin.empty ()) {
312
+ origin = " *" ;
313
+ }
314
+ response << " Access-Control-Allow-Origin: " << origin << " \r\n " ;
315
+ response << " Access-Control-Allow-Credentials: true\r\n " ;
316
+ response << " Access-Control-Allow-Headers: Content-Type,Authorization,Origin,Accept\r\n " ;
317
+ response << " Access-Control-Allow-Methods: OPTIONS, GET, POST, PUT, DELETE\r\n " ;
318
+ }
319
+
320
+ response << " Content-Type: " << contentType << " \r\n " ;
291
321
response << " Content-Length: " << body.Size () << " \r\n " ;
292
322
response << " \r\n " ;
293
323
response << body;
@@ -296,21 +326,9 @@ class THttpMonLegacyActorRequest : public TActorBootstrapped<THttpMonLegacyActor
296
326
}
297
327
298
328
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 ();
329
+ NYql::TIssues issues;
330
+ issues.AddIssue (error);
331
+ ReplyErrorAndPassAway (Ydb::StatusIds::UNAUTHORIZED, issues, false );
314
332
}
315
333
316
334
void SendRequest (const NKikimr::NGRpcService::TEvRequestAuthAndCheckResult* result = nullptr ) {
0 commit comments