public async ValueTask HandlePath(RequestHandlerContext reqCtx) { var context = reqCtx.HttpContext; var tryMatch = _trie.TryMatch(context.Request.Method, context.Request.Path.Value); if (tryMatch.Value == null) { var exception = new RouteNotFoundException($"There is no handler for path: {context.Request.Method} {context.Request.Path.Value}{context.Request.QueryString}"); AssertClientVersion(context, exception); throw exception; } reqCtx.RavenServer = _ravenServer; reqCtx.RouteMatch = tryMatch.Match; var tuple = tryMatch.Value.TryGetHandler(reqCtx); var handler = tuple.Item1 ?? await tuple.Item2; reqCtx.Database?.Metrics?.Requests.RequestsPerSec.Mark(); _serverMetrics.Requests.RequestsPerSec.Mark(); Interlocked.Increment(ref _serverMetrics.Requests.ConcurrentRequestsCount); try { _ravenServer.Statistics.LastRequestTime = SystemTime.UtcNow; if (handler == null) { if (_auditLog != null) { _auditLog.Info($"Invalid request {context.Request.Method} {context.Request.Path} by " + $"(Cert: {context.Connection.ClientCertificate?.Subject} ({context.Connection.ClientCertificate?.Thumbprint}) {context.Connection.RemoteIpAddress}:{context.Connection.RemotePort})"); } context.Response.StatusCode = (int)HttpStatusCode.BadRequest; using (var ctx = JsonOperationContext.ShortTermSingleUse()) using (var writer = new BlittableJsonTextWriter(ctx, context.Response.Body)) { ctx.Write(writer, new DynamicJsonValue { ["Type"] = "Error", ["Message"] = $"There is no handler for {context.Request.Method} {context.Request.Path}" }); } return; } if (_ravenServer.Configuration.Security.AuthenticationEnabled) { var authResult = TryAuthorize(tryMatch.Value, context, reqCtx.Database); if (authResult == false) { return; } } if (reqCtx.Database != null) { using (reqCtx.Database.DatabaseInUse(tryMatch.Value.SkipUsagesCount)) await handler(reqCtx); } else { await handler(reqCtx); } } finally { Interlocked.Decrement(ref _serverMetrics.Requests.ConcurrentRequestsCount); } }
public async ValueTask <string> HandlePath(HttpContext context, string method, string path) { var tryMatch = _trie.TryMatch(method, path); if (tryMatch.Value == null) { var exception = new RouteNotFoundException($"There is no handler for path: {method} {path}{context.Request.QueryString}"); AssertClientVersion(context, exception); throw exception; } var reqCtx = new RequestHandlerContext { HttpContext = context, RavenServer = _ravenServer, RouteMatch = tryMatch.Match }; var tuple = tryMatch.Value.TryGetHandler(reqCtx); var handler = tuple.Item1 ?? await tuple.Item2; reqCtx.Database?.Metrics?.Requests.RequestsPerSec.Mark(); _serverMetrics.Requests.RequestsPerSec.Mark(); Interlocked.Increment(ref _serverMetrics.Requests.ConcurrentRequestsCount); try { _ravenServer.Statistics.LastRequestTime = SystemTime.UtcNow; if (handler == null) { var auditLog = LoggingSource.AuditLog.IsInfoEnabled ? LoggingSource.AuditLog.GetLogger("RequestRouter", "Audit") : null; if (auditLog != null) { auditLog.Info($"Invalid request {context.Request.Method} {context.Request.Path} by " + $"(Cert: {context.Connection.ClientCertificate?.Subject} ({context.Connection.ClientCertificate?.Thumbprint}) {context.Connection.RemoteIpAddress}:{context.Connection.RemotePort})"); } context.Response.StatusCode = (int)HttpStatusCode.BadRequest; using (var ctx = JsonOperationContext.ShortTermSingleUse()) using (var writer = new BlittableJsonTextWriter(ctx, context.Response.Body)) { ctx.Write(writer, new DynamicJsonValue { ["Type"] = "Error", ["Message"] = $"There is no handler for {context.Request.Method} {context.Request.Path}" }); } return(null); } if (_ravenServer.Configuration.Security.AuthenticationEnabled) { var authResult = TryAuthorize(tryMatch.Value, context, reqCtx.Database); if (authResult == false) { return(reqCtx.Database?.Name); } } if (reqCtx.Database != null) { using (reqCtx.Database.DatabaseInUse(tryMatch.Value.SkipUsagesCount)) { if (reqCtx.HttpContext.Response.Headers.TryGetValue(Constants.Headers.LastKnownClusterTransactionIndex, out var value) && long.TryParse(value, out var index) && index < reqCtx.Database.RachisLogIndexNotifications.LastModifiedIndex) { await reqCtx.Database.RachisLogIndexNotifications.WaitForIndexNotification(index, reqCtx.HttpContext.RequestAborted); } await handler(reqCtx); } } else { await handler(reqCtx); } } finally { Interlocked.Decrement(ref _serverMetrics.Requests.ConcurrentRequestsCount); } return(reqCtx.Database?.Name); }
public async ValueTask HandlePath(RequestHandlerContext reqCtx) { var context = reqCtx.HttpContext; var tryMatch = _trie.TryMatch(context.Request.Method, context.Request.Path.Value); if (tryMatch.Value == null) { var exception = new RouteNotFoundException($"There is no handler for path: {context.Request.Method} {context.Request.Path.Value}{context.Request.QueryString}"); AssertClientVersion(context, exception); throw exception; } reqCtx.RavenServer = _ravenServer; reqCtx.RouteMatch = tryMatch.Match; var tuple = tryMatch.Value.TryGetHandler(reqCtx); var handler = tuple.Item1 ?? await tuple.Item2; reqCtx.Database?.Metrics?.Requests.RequestsPerSec.Mark(); _serverMetrics.Requests.RequestsPerSec.Mark(); Interlocked.Increment(ref _serverMetrics.Requests.ConcurrentRequestsCount); try { if (handler == null) { var auditLog = LoggingSource.AuditLog.IsInfoEnabled ? LoggingSource.AuditLog.GetLogger("RequestRouter", "Audit") : null; if (auditLog != null) { auditLog.Info($"Invalid request {context.Request.Method} {context.Request.Path} by " + $"(Cert: {context.Connection.ClientCertificate?.Subject} ({context.Connection.ClientCertificate?.Thumbprint}) {context.Connection.RemoteIpAddress}:{context.Connection.RemotePort})"); } context.Response.StatusCode = (int)HttpStatusCode.BadRequest; using (var ctx = JsonOperationContext.ShortTermSingleUse()) using (var writer = new BlittableJsonTextWriter(ctx, context.Response.Body)) { ctx.Write(writer, new DynamicJsonValue { ["Type"] = "Error", ["Message"] = $"There is no handler for {context.Request.Method} {context.Request.Path}" }); } return; } var skipAuthorization = false; if (tryMatch.Value.CorsMode != CorsMode.None) { RequestHandler.SetupCORSHeaders(context, reqCtx.RavenServer.ServerStore, tryMatch.Value.CorsMode); // don't authorize preflight requests: https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html skipAuthorization = context.Request.Method == "OPTIONS"; } var status = RavenServer.AuthenticationStatus.ClusterAdmin; try { if (_ravenServer.Configuration.Security.AuthenticationEnabled && skipAuthorization == false) { if (TryAuthorize(tryMatch.Value, context, reqCtx.Database, out status) == false) { return; } } } finally { if (tryMatch.Value.SkipLastRequestTimeUpdate == false) { var now = SystemTime.UtcNow; if (now - _lastRequestTimeUpdated >= LastRequestTimeUpdateFrequency) { _ravenServer.Statistics.LastRequestTime = now; _lastRequestTimeUpdated = now; } if (now - _lastAuthorizedNonClusterAdminRequestTime >= LastRequestTimeUpdateFrequency && skipAuthorization == false) { switch (status) { case RavenServer.AuthenticationStatus.Allowed: case RavenServer.AuthenticationStatus.Operator: { _ravenServer.Statistics.LastAuthorizedNonClusterAdminRequestTime = now; _lastAuthorizedNonClusterAdminRequestTime = now; break; } case RavenServer.AuthenticationStatus.None: case RavenServer.AuthenticationStatus.NoCertificateProvided: case RavenServer.AuthenticationStatus.UnfamiliarCertificate: case RavenServer.AuthenticationStatus.UnfamiliarIssuer: case RavenServer.AuthenticationStatus.ClusterAdmin: case RavenServer.AuthenticationStatus.Expired: case RavenServer.AuthenticationStatus.NotYetValid: break; default: ThrowUnknownAuthStatus(status); break; } } } } if (reqCtx.Database != null) { if (tryMatch.Value.DisableOnCpuCreditsExhaustion && _ravenServer.CpuCreditsBalance.FailoverAlertRaised.IsRaised()) { RejectRequestBecauseOfCpuThreshold(context); return; } using (reqCtx.Database.DatabaseInUse(tryMatch.Value.SkipUsagesCount)) { if (context.Request.Headers.TryGetValue(Constants.Headers.LastKnownClusterTransactionIndex, out var value) && long.TryParse(value, out var index) && index > reqCtx.Database.RachisLogIndexNotifications.LastModifiedIndex) { await reqCtx.Database.RachisLogIndexNotifications.WaitForIndexNotification(index, context.RequestAborted); } await handler(reqCtx); } } else { await handler(reqCtx); } } finally { Interlocked.Decrement(ref _serverMetrics.Requests.ConcurrentRequestsCount); } }