Exemple #1
0
        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);
            }
        }
Exemple #2
0
        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);
        }
Exemple #3
0
        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);
            }
        }