예제 #1
0
 public Task GetCpuCredits()
 {
     using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context))
         using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream()))
         {
             var json = Server.CpuCreditsBalance.ToJson();
             writer.WriteObject(context.ReadObject(json, "cpu/credits"));
             return(Task.CompletedTask);
         }
 }
예제 #2
0
        protected override void PersistFields(JsonOperationContext context, BlittableJsonTextWriter writer)
        {
            var builder = IndexDefinition.ToJson();

            using (var json = context.ReadObject(builder, nameof(IndexDefinition), BlittableJsonDocumentBuilder.UsageMode.ToDisk))
            {
                writer.WritePropertyName(nameof(IndexDefinition));
                writer.WriteObject(json);
            }
        }
예제 #3
0
        public Task GetClientConfiguration()
        {
            var inherit = GetBoolValueQueryString("inherit", required: false) ?? true;

            var  configuration       = Database.ClientConfiguration;
            long etag                = configuration?.Etag ?? -1;
            var  serverConfiguration = GetServerClientConfiguration(out long serverIndex);

            etag = Hashing.Combine(etag, serverConfiguration?.Etag ?? -2);
            if (inherit)
            {
                if (configuration == null || configuration.Disabled)
                {
                    if (serverConfiguration != null)
                    {
                        configuration = serverConfiguration;
                        etag          = serverIndex;
                    }
                }
            }

            using (ContextPool.AllocateOperationContext(out JsonOperationContext context))
            {
                BlittableJsonReaderObject clientConfigurationJson = null;
                if (configuration != null)
                {
                    var val = configuration.ToJson();
                    clientConfigurationJson = context.ReadObject(val, Constants.Configuration.ClientId);
                }

                using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream()))
                {
                    writer.WriteStartObject();

                    writer.WritePropertyName(nameof(GetClientConfigurationOperation.Result.Etag));
                    writer.WriteInteger(etag);
                    writer.WriteComma();

                    writer.WritePropertyName(nameof(GetClientConfigurationOperation.Result.Configuration));
                    if (clientConfigurationJson != null)
                    {
                        writer.WriteObject(clientConfigurationJson);
                    }
                    else
                    {
                        writer.WriteNull();
                    }

                    writer.WriteEndObject();
                }
            }

            return(Task.CompletedTask);
        }
예제 #4
0
        public Task WhoAmI()
        {
            var feature    = HttpContext.Features.Get <IHttpAuthenticationFeature>() as RavenServer.AuthenticateConnection;
            var clientCert = feature?.Certificate;

            if (clientCert == null)
            {
                return(NoContent());
            }

            using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext ctx))
            {
                BlittableJsonReaderObject certificate;
                using (ctx.OpenReadTransaction())
                    certificate = ServerStore.Cluster.Read(ctx, Constants.Certificates.Prefix + clientCert.Thumbprint);

                if (certificate == null && clientCert.Equals(Server.Certificate.Certificate))
                {
                    var certKey = Constants.Certificates.Prefix + clientCert.Thumbprint;
                    using (ctx.OpenReadTransaction())
                        certificate = ServerStore.Cluster.Read(ctx, certKey) ??
                                      ServerStore.Cluster.GetLocalState(ctx, certKey);

                    if (certificate == null && Server.Certificate.Certificate != null)
                    {
                        // Since we didn't go through EnsureNotPassive(), the server certificate is not registered yet so we'll add it to the local state.
                        var serverCertDef = new CertificateDefinition
                        {
                            Name              = "Server Certificate",
                            Certificate       = Convert.ToBase64String(Server.Certificate.Certificate.Export(X509ContentType.Cert)),
                            Permissions       = new Dictionary <string, DatabaseAccess>(),
                            SecurityClearance = SecurityClearance.ClusterNode,
                            Thumbprint        = Server.Certificate.Certificate.Thumbprint,
                            NotAfter          = Server.Certificate.Certificate.NotAfter
                        };

                        certificate = ctx.ReadObject(serverCertDef.ToJson(), "Server/Certificate/Definition");
                        using (var tx = ctx.OpenWriteTransaction())
                        {
                            ServerStore.Cluster.PutLocalState(ctx, Constants.Certificates.Prefix + Server.Certificate.Certificate.Thumbprint, certificate);
                            tx.Commit();
                        }
                    }
                }
                using (var writer = new BlittableJsonTextWriter(ctx, ResponseBodyStream()))
                {
                    writer.WriteObject(certificate);
                }
            }

            return(Task.CompletedTask);
        }
예제 #5
0
        private void HandleException(JsonOperationContext context, BlittableJsonTextWriter writer, Exception e, string url, string query)
        {
            var djv = new DynamicJsonValue
            {
                [nameof(ExceptionDispatcher.ExceptionSchema.Url)]     = url + query,
                [nameof(ExceptionDispatcher.ExceptionSchema.Type)]    = e.GetType().FullName,
                [nameof(ExceptionDispatcher.ExceptionSchema.Message)] = e.Message,
                [nameof(ExceptionDispatcher.ExceptionSchema.Error)]   = e.ToString()
            };

            using (var json = context.ReadObject(djv, "exception"))
                writer.WriteObject(json);
        }
예제 #6
0
        public Task Report()
        {
            using (ContextPool.AllocateOperationContext(out DocumentsOperationContext context))
            {
                using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream()))
                {
                    writer.WriteStartObject();

                    writer.WritePropertyName("BasePath");
                    writer.WriteString(Database.Configuration.Core.DataDirectory.FullPath);
                    writer.WriteComma();

                    writer.WritePropertyName("Results");
                    writer.WriteStartArray();
                    var first = true;
                    foreach (var env in Database.GetAllStoragesEnvironment())
                    {
                        if (first == false)
                        {
                            writer.WriteComma();
                        }

                        first = false;

                        writer.WriteStartObject();

                        writer.WritePropertyName("Name");
                        writer.WriteString(env.Name);
                        writer.WriteComma();

                        writer.WritePropertyName("Type");
                        writer.WriteString(env.Type.ToString());
                        writer.WriteComma();

                        var djv = (DynamicJsonValue)TypeConverter.ToBlittableSupportedType(GetReport(env));
                        writer.WritePropertyName("Report");
                        writer.WriteObject(context.ReadObject(djv, env.Name));

                        writer.WriteEndObject();
                    }

                    writer.WriteEndArray();

                    writer.WriteEndObject();
                }
            }

            return(Task.CompletedTask);
        }
예제 #7
0
        protected override void PersistMapFields(JsonOperationContext context, BlittableJsonTextWriter writer)
        {
            writer.WritePropertyName(nameof(MapFields));
            writer.WriteStartArray();
            var first = true;

            foreach (var field in MapFields.Values.Select(x => x.As <AutoIndexField>()))
            {
                if (first == false)
                {
                    writer.WriteComma();
                }

                writer.WriteStartObject();

                writer.WritePropertyName(nameof(field.Name));
                writer.WriteString(field.Name);
                writer.WriteComma();

                writer.WritePropertyName(nameof(field.Indexing));
                writer.WriteString(field.Indexing.ToString());
                writer.WriteComma();

                writer.WritePropertyName(nameof(field.Aggregation));
                writer.WriteInteger((int)field.Aggregation);
                writer.WriteComma();

                writer.WritePropertyName(nameof(field.Spatial));
                if (field.Spatial == null)
                {
                    writer.WriteNull();
                }
                else
                {
                    writer.WriteObject(DocumentConventions.DefaultForServer.Serialization.DefaultConverter.ToBlittable(field.Spatial, context));
                }
                writer.WriteComma();

                writer.WritePropertyName(nameof(field.HasSuggestions));
                writer.WriteBool(field.HasSuggestions);

                writer.WriteEndObject();

                first = false;
            }
            writer.WriteEndArray();
        }
예제 #8
0
        public Task EnvironmentReport()
        {
            var name         = GetStringQueryString("name");
            var typeAsString = GetStringQueryString("type");
            var details      = GetBoolValueQueryString("details", required: false) ?? false;

            StorageEnvironmentWithType.StorageEnvironmentType type;
            if (Enum.TryParse(typeAsString, out type) == false)
            {
                throw new InvalidOperationException("Query string value 'type' is not a valid environment type: " + typeAsString);
            }

            var env = Database.GetAllStoragesEnvironment()
                      .FirstOrDefault(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase) && x.Type == type);

            if (env == null)
            {
                HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
                return(Task.CompletedTask);
            }

            DocumentsOperationContext context;

            using (ContextPool.AllocateOperationContext(out context))
            {
                using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream()))
                {
                    writer.WriteStartObject();

                    writer.WritePropertyName("Name");
                    writer.WriteString(env.Name);
                    writer.WriteComma();

                    writer.WritePropertyName("Type");
                    writer.WriteString(env.Type.ToString());
                    writer.WriteComma();

                    var djv = (DynamicJsonValue)TypeConverter.ToBlittableSupportedType(GetDetailedReport(env, details));
                    writer.WritePropertyName("Report");
                    writer.WriteObject(context.ReadObject(djv, env.Name));

                    writer.WriteEndObject();
                }
            }

            return(Task.CompletedTask);
        }
예제 #9
0
        public static string ConvertResultToString(ScriptRunnerResult result)
        {
            var ms = new MemoryStream();

            using (var ctx = JsonOperationContext.ShortTermSingleUse())
                using (var writer = new BlittableJsonTextWriter(ctx, ms))
                {
                    writer.WriteStartObject();

                    writer.WritePropertyName("Result");

                    if (result.IsNull)
                    {
                        writer.WriteNull();
                    }
                    else if (result.RawJsValue.IsBoolean())
                    {
                        writer.WriteBool(result.RawJsValue.AsBoolean());
                    }
                    else if (result.RawJsValue.IsString())
                    {
                        writer.WriteString(result.RawJsValue.AsString());
                    }
                    else if (result.RawJsValue.IsDate())
                    {
                        var date = result.RawJsValue.AsDate();
                        writer.WriteString(date.ToDateTime().ToString("O"));
                    }
                    else if (result.RawJsValue.IsNumber())
                    {
                        writer.WriteDouble(result.RawJsValue.AsNumber());
                    }
                    else
                    {
                        writer.WriteObject(result.TranslateToObject(ctx));
                    }

                    writer.WriteEndObject();
                    writer.Flush();
                }

            var str = Encoding.UTF8.GetString(ms.ToArray());

            return(str);
        }
예제 #10
0
        public Task WhoAmI()
        {
            var feature    = HttpContext.Features.Get <IHttpAuthenticationFeature>() as RavenServer.AuthenticateConnection;
            var clientCert = feature?.Certificate;

            using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext ctx))
                using (ctx.OpenReadTransaction())
                {
                    var certificate = ServerStore.Cluster.Read(ctx, Constants.Certificates.Prefix + clientCert?.Thumbprint);

                    using (var writer = new BlittableJsonTextWriter(ctx, ResponseBodyStream()))
                    {
                        writer.WriteObject(certificate);
                    }
                }

            return(Task.CompletedTask);
        }
예제 #11
0
        public Task PostScriptTest()
        {
            using (Database.DocumentsStorage.ContextPool.AllocateOperationContext(out DocumentsOperationContext context))
            {
                var dbDoc      = context.ReadForMemory(RequestBodyStream(), "TestSqlEtlScript");
                var testScript = JsonDeserializationServer.TestSqlEtlScript(dbDoc);

                var result = (SqlEtlTestScriptResult)SqlEtl.TestScript(testScript, Database, ServerStore, context);

                using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream()))
                {
                    var djv = (DynamicJsonValue)TypeConverter.ToBlittableSupportedType(result);
                    writer.WriteObject(context.ReadObject(djv, "et/sql/test"));
                }
            }

            return(Task.CompletedTask);
        }
예제 #12
0
        public Task PostSimulateSqlReplication()
        {
            using (Database.DocumentsStorage.ContextPool.AllocateOperationContext(out DocumentsOperationContext context))
            {
                context.OpenReadTransaction();

                var dbDoc = context.ReadForMemory(RequestBodyStream(), "SimulateSqlReplicationResult");
                var simulateSqlReplication = JsonDeserializationServer.SimulateSqlReplication(dbDoc);
                var result = SqlEtl.SimulateSqlEtl(simulateSqlReplication, Database, ServerStore, context);

                using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream()))
                {
                    var djv = (DynamicJsonValue)TypeConverter.ToBlittableSupportedType(result);
                    writer.WriteObject(context.ReadObject(djv, "et/sql/simulate"));
                }
            }

            return(Task.CompletedTask);
        }
예제 #13
0
        public Task GetConfiguration()
        {
            using (ServerStore.ContextPool.AllocateOperationContext(out JsonOperationContext context))
                using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream()))
                {
                    var djv = new DynamicJsonValue
                    {
                        [nameof(GetLogsConfigurationResult.CurrentMode)] = LoggingSource.Instance.LogMode,
                        [nameof(GetLogsConfigurationResult.Mode)]        = ServerStore.Configuration.Logs.Mode,
                        [nameof(GetLogsConfigurationResult.Path)]        = ServerStore.Configuration.Logs.Path.FullPath,
                        [nameof(GetLogsConfigurationResult.UseUtcTime)]  = ServerStore.Configuration.Logs.UseUtcTime
                    };

                    var json = context.ReadObject(djv, "logs/configuration");

                    writer.WriteObject(json);
                }

            return(Task.CompletedTask);
        }
예제 #14
0
        private void WriteIntermidiateResults(List <GraphQueryRunner.Match> matches)
        {
            _writer.WritePropertyName("Results");
            _writer.WriteStartArray();
            var first = true;

            foreach (var match in matches)
            {
                if (first == false)
                {
                    _writer.WriteComma();
                }

                first = false;
                var djv = new DynamicJsonValue();
                match.PopulateVertices(djv);
                _writer.WriteObject(_ctx.ReadObject(djv, null));
            }

            _writer.WriteEndArray();
        }
        public Task GetStudioConfiguration()
        {
            using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context))
            {
                using (context.OpenReadTransaction())
                {
                    var studioConfigurationJson = ServerStore.Cluster.Read(context, Constants.Configuration.StudioId, out long _);
                    if (studioConfigurationJson == null)
                    {
                        HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
                        return(Task.CompletedTask);
                    }

                    using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream()))
                    {
                        writer.WriteObject(studioConfigurationJson);
                    }
                }
            }

            return(Task.CompletedTask);
        }
예제 #16
0
        public Task GetOids()
        {
            using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context))
                using (context.OpenReadTransaction())
                {
                    using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream()))
                    {
                        var djv = new DynamicJsonValue
                        {
                            [nameof(SnmpOids.Server)]    = SnmpOids.Server.ToJson(),
                            [nameof(SnmpOids.Cluster)]   = SnmpOids.Cluster.ToJson(),
                            [nameof(SnmpOids.Databases)] = SnmpOids.Databases.ToJson(ServerStore, context)
                        };

                        var json = context.ReadObject(djv, "snmp/oids");

                        writer.WriteObject(json);
                    }
                }

            return(Task.CompletedTask);
        }
예제 #17
0
        public Task GetStudioConfiguration()
        {
            var configuration = Database.StudioConfiguration;

            if (configuration == null)
            {
                HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
                return(Task.CompletedTask);
            }

            using (ContextPool.AllocateOperationContext(out JsonOperationContext context))
            {
                var val = configuration.ToJson();
                var clientConfigurationJson = context.ReadObject(val, Constants.Configuration.StudioId);

                using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream()))
                {
                    writer.WriteObject(clientConfigurationJson);
                }
            }

            return(Task.CompletedTask);
        }
예제 #18
0
        public Task Operation()
        {
            var id = GetLongQueryString("id");
            // ReSharper disable once PossibleInvalidOperationException
            var operation = Database.Operations.GetOperation(id.Value);

            if (operation == null)
            {
                HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
                return(Task.CompletedTask);
            }

            DocumentsOperationContext context;

            using (ContextPool.AllocateOperationContext(out context))
            {
                using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream()))
                {
                    writer.WriteObject(context.ReadObject(operation.ToJson(), "operation"));
                }
            }

            return(Task.CompletedTask);
        }
        public static void WriteIndexStats(this BlittableJsonTextWriter writer, JsonOperationContext context, IndexStats stats)
        {
            var djv = (DynamicJsonValue)TypeConverter.ToBlittableSupportedType(stats);

            writer.WriteObject(context.ReadObject(djv, "index/stats"));
        }
        public static void WriteTreePagesRecursively(this BlittableJsonTextWriter writer, IEnumerable <ReduceTreePage> pages)
        {
            var first = true;

            foreach (var page in pages)
            {
                if (first == false)
                {
                    writer.WriteComma();
                }

                writer.WriteStartObject();

                writer.WritePropertyName(nameof(TreePage.PageNumber));
                writer.WriteInteger(page.PageNumber);
                writer.WriteComma();

                writer.WritePropertyName(nameof(ReduceTreePage.AggregationResult));
                if (page.AggregationResult != null)
                {
                    writer.WriteObject(page.AggregationResult);
                }
                else
                {
                    writer.WriteNull();
                }
                writer.WriteComma();

                writer.WritePropertyName(nameof(ReduceTreePage.Children));
                if (page.Children != null)
                {
                    writer.WriteStartArray();
                    WriteTreePagesRecursively(writer, page.Children);
                    writer.WriteEndArray();
                }
                else
                {
                    writer.WriteNull();
                }
                writer.WriteComma();

                writer.WritePropertyName(nameof(ReduceTreePage.Entries));
                if (page.Entries != null)
                {
                    writer.WriteStartArray();

                    var firstEntry = true;
                    foreach (var entry in page.Entries)
                    {
                        if (firstEntry == false)
                        {
                            writer.WriteComma();
                        }

                        writer.WriteStartObject();

                        writer.WritePropertyName(nameof(MapResultInLeaf.Data));
                        writer.WriteObject(entry.Data);
                        writer.WriteComma();

                        writer.WritePropertyName(nameof(MapResultInLeaf.Source));
                        writer.WriteString(entry.Source);

                        writer.WriteEndObject();

                        firstEntry = false;
                    }

                    writer.WriteEndArray();
                }
                else
                {
                    writer.WriteNull();
                }

                writer.WriteEndObject();
                first = false;
            }
        }
예제 #21
0
        public static void WaitForIndexing(IDocumentStore store, string dbName = null, TimeSpan?timeout = null)
        {
            var admin = store.Maintenance.ForDatabase(dbName);

            timeout = timeout ?? (Debugger.IsAttached
                          ? TimeSpan.FromMinutes(15)
                          : TimeSpan.FromMinutes(1));

            var sp = Stopwatch.StartNew();

            while (sp.Elapsed < timeout.Value)
            {
                var databaseStatistics = admin.Send(new GetStatisticsOperation());
                var indexes            = databaseStatistics.Indexes
                                         .Where(x => x.State != IndexState.Disabled);

                if (indexes.All(x => x.IsStale == false && x.Name.StartsWith("ReplacementOf/") == false))
                {
                    return;
                }

                if (databaseStatistics.Indexes.Any(x => x.State == IndexState.Error))
                {
                    break;
                }
                Thread.Sleep(32);
            }

            var perf   = admin.Send(new GetIndexPerformanceStatisticsOperation());
            var errors = admin.Send(new GetIndexErrorsOperation());
            var stats  = admin.Send(new GetIndexesStatisticsOperation());

            var total = new
            {
                Errors      = errors,
                Stats       = stats,
                Performance = perf
            };

            var file = Path.GetTempFileName() + ".json";

            using (var stream = File.Open(file, FileMode.OpenOrCreate))
                using (var context = JsonOperationContext.ShortTermSingleUse())
                    using (var writer = new BlittableJsonTextWriter(context, stream))
                    {
                        var djv  = (DynamicJsonValue)TypeConverter.ToBlittableSupportedType(total);
                        var json = context.ReadObject(djv, "errors");
                        writer.WriteObject(json);
                        writer.Flush();
                    }

            var statistics = admin.Send(new GetStatisticsOperation());

            var corrupted = statistics.Indexes.Where(x => x.State == IndexState.Error).ToList();

            if (corrupted.Count > 0)
            {
                throw new InvalidOperationException(
                          $"The following indexes are with error state: {string.Join(",", corrupted.Select(x => x.Name))} - details at " + file);
            }

            throw new TimeoutException("The indexes stayed stale for more than " + timeout.Value + ", stats at " + file);
        }
예제 #22
0
        private async Task RequestHandler(HttpContext context)
        {
            string database = null;

            try
            {
                context.Response.StatusCode = (int)HttpStatusCode.OK;
                context.Response.Headers["Content-Type"] = "application/json; charset=utf-8";

                var sp = Stopwatch.StartNew();
                database = await _router.HandlePath(context, context.Request.Method, context.Request.Path.Value);

                sp.Stop();

                if (_logger.IsInfoEnabled && SkipHttpLogging == false)
                {
                    _logger.Info($"{context.Request.Method} {context.Request.Path.Value}?{context.Request.QueryString.Value} - {context.Response.StatusCode} - {sp.ElapsedMilliseconds:#,#;;0} ms");
                }

                if (TrafficWatchManager.HasRegisteredClients)
                {
                    LogTrafficWatch(context, sp.ElapsedMilliseconds, database);
                }
            }
            catch (Exception e)
            {
                if (TrafficWatchManager.HasRegisteredClients)
                {
                    LogTrafficWatch(context, 0, database ?? "N/A");
                }

                if (context.RequestAborted.IsCancellationRequested)
                {
                    return;
                }

                if (context.Request.Headers.TryGetValue(Constants.Headers.ClientVersion, out var versions))
                {
                    var version = versions.ToString();
                    if (version.Length > 0 && version[0] != RavenVersionAttribute.Instance.MajorVersionAsChar)
                    {
                        e = new ClientVersionMismatchException($"RavenDB does not support interaction between Client API and Server when major version does not match. Client: {version}. Server: {RavenVersionAttribute.Instance.AssemblyVersion}", e);
                    }
                }

                MaybeSetExceptionStatusCode(context, e);

                using (_server.ServerStore.ContextPool.AllocateOperationContext(out JsonOperationContext ctx))
                {
                    var djv = new DynamicJsonValue
                    {
                        [nameof(ExceptionDispatcher.ExceptionSchema.Url)]     = $"{context.Request.Path}{context.Request.QueryString}",
                        [nameof(ExceptionDispatcher.ExceptionSchema.Type)]    = e.GetType().FullName,
                        [nameof(ExceptionDispatcher.ExceptionSchema.Message)] = e.Message,
                        [nameof(ExceptionDispatcher.ExceptionSchema.Error)]   = e.ToString()
                    };

#if EXCEPTION_ERROR_HUNT
                    var f = Guid.NewGuid() + ".error";
                    File.WriteAllText(f,
                                      $"{context.Request.Path}{context.Request.QueryString}" + Environment.NewLine + errorString);
#endif

                    MaybeAddAdditionalExceptionData(djv, e);

                    using (var writer = new BlittableJsonTextWriter(ctx, context.Response.Body))
                    {
                        var json = ctx.ReadObject(djv, "exception");
                        writer.WriteObject(json);
                    }

#if EXCEPTION_ERROR_HUNT
                    File.Delete(f);
#endif
                }
            }
        }
예제 #23
0
        public Task WhoAmI()
        {
            var clientCert = GetCurrentCertificate();

            if (clientCert == null)
            {
                return(NoContent());
            }

            using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext ctx))
            {
                var certKey = Constants.Certificates.Prefix + clientCert.Thumbprint;
                BlittableJsonReaderObject certificate;
                using (ctx.OpenReadTransaction())
                    certificate = ServerStore.Cluster.Read(ctx, certKey) ??
                                  ServerStore.Cluster.GetLocalState(ctx, certKey);

                if (certificate == null)
                {
                    // The client certificate is not registered in the ServerStore.
                    // Let's check if the client is using the server certificate or one of the well known admin certs.

                    var wellKnown = ServerStore.Configuration.Security.WellKnownAdminCertificates;

                    if (clientCert.Equals(Server.Certificate.Certificate))
                    {
                        if (Server.Certificate.Certificate != null)
                        {
                            var serverCertDef = new CertificateDefinition
                            {
                                Name              = "Server Certificate",
                                Certificate       = Convert.ToBase64String(Server.Certificate.Certificate.Export(X509ContentType.Cert)),
                                Permissions       = new Dictionary <string, DatabaseAccess>(),
                                SecurityClearance = SecurityClearance.ClusterNode,
                                Thumbprint        = Server.Certificate.Certificate.Thumbprint,
                                NotAfter          = Server.Certificate.Certificate.NotAfter
                            };

                            certificate = ctx.ReadObject(serverCertDef.ToJson(), "Server/Certificate/Definition");
                        }
                    }
                    else if (wellKnown != null && wellKnown.Contains(clientCert.Thumbprint, StringComparer.OrdinalIgnoreCase))
                    {
                        var serverCertDef = new CertificateDefinition
                        {
                            Name              = "Well Known Admin Certificate",
                            Permissions       = new Dictionary <string, DatabaseAccess>(),
                            SecurityClearance = SecurityClearance.ClusterAdmin,
                            Thumbprint        = clientCert.Thumbprint,
                        };
                        certificate = ctx.ReadObject(serverCertDef.ToJson(), "WellKnown/Certificate/Definition");
                    }
                }

                using (var writer = new BlittableJsonTextWriter(ctx, ResponseBodyStream()))
                {
                    writer.WriteObject(certificate);
                }
            }

            return(Task.CompletedTask);
        }
예제 #24
0
        private async Task RequestHandler(HttpContext context)
        {
            try
            {
                context.Response.StatusCode = 200;
                var sp     = Stopwatch.StartNew();
                var tenant = await _router.HandlePath(context, context.Request.Method, context.Request.Path.Value);

                sp.Stop();

                if (_logger.IsInfoEnabled)
                {
                    _logger.Info($"{context.Request.Method} {context.Request.Path.Value}?{context.Request.QueryString.Value} - {context.Response.StatusCode} - {sp.ElapsedMilliseconds:#,#;;0} ms");
                }

                if (TrafficWatchManager.HasRegisteredClients)
                {
                    var requestId = Interlocked.Increment(ref _requestId);

                    var twn = new TrafficWatchNotification
                    {
                        TimeStamp           = DateTime.UtcNow,
                        RequestId           = requestId,                       // counted only for traffic watch
                        HttpMethod          = context.Request.Method ?? "N/A", // N/A ?
                        ElapsedMilliseconds = sp.ElapsedMilliseconds,
                        ResponseStatusCode  = context.Response.StatusCode,
                        RequestUri          = context.Request.GetEncodedUrl(),
                        AbsoluteUri         = $@"{context.Request.Scheme}://{context.Request.Host}",
                        TenantName          = tenant ?? "N/A",
                        CustomInfo          = "",   // TODO: Implement
                        InnerRequestsCount  = 0,    // TODO: Implement
                        QueryTimings        = null, // TODO: Implement
                    };

                    TrafficWatchManager.DispatchMessage(twn);
                }
            }
            catch (Exception e)
            {
                if (context.RequestAborted.IsCancellationRequested)
                {
                    return;
                }
                //TODO: special handling for argument exception (400 bad request)
                //TODO: database not found (503)
                //TODO: operaton cancelled (timeout)
                //TODO: Invalid data exception 422


                //TODO: Proper json output, not like this
                var response = context.Response;

                var documentConflictException = e as DocumentConflictException;
                if (response.HasStarted == false)
                {
                    if (documentConflictException != null)
                    {
                        response.StatusCode = 409;
                    }
                    else if (response.StatusCode < 400)
                    {
                        response.StatusCode = 500;
                    }
                }


                JsonOperationContext ctx;
                using (_server.ServerStore.ContextPool.AllocateOperationContext(out ctx))
                {
                    var djv = new DynamicJsonValue
                    {
                        ["Url"]     = $"{context.Request.Path}?{context.Request.QueryString}",
                        ["Type"]    = e.GetType().FullName,
                        ["Message"] = e.Message
                    };

                    string errorString;

                    try
                    {
                        errorString = e.ToAsyncString();
                    }
                    catch (Exception)
                    {
                        errorString = e.ToString();
                    }

                    djv["Error"] = errorString;

                    var indexCompilationException = e as IndexCompilationException;
                    if (indexCompilationException != null)
                    {
                        djv[nameof(IndexCompilationException.IndexDefinitionProperty)] =
                            indexCompilationException.IndexDefinitionProperty;
                        djv[nameof(IndexCompilationException.ProblematicText)] =
                            indexCompilationException.ProblematicText;
                    }

                    if (documentConflictException != null)
                    {
                        djv["ConflictInfo"] = ReplicationUtils.GetJsonForConflicts(
                            documentConflictException.DocId,
                            documentConflictException.Conflicts);
                    }

                    using (var writer = new BlittableJsonTextWriter(ctx, response.Body))
                    {
                        var json = ctx.ReadObject(djv, "exception");
                        writer.WriteObject(json);
                    }
                }
            }
        }
예제 #25
0
        public static void WriteIndexQuery(this BlittableJsonTextWriter writer, DocumentConventions conventions, JsonOperationContext context, IndexQuery query)
        {
            writer.WriteStartObject();

            writer.WritePropertyName(nameof(query.Query));
            writer.WriteString(query.Query);
            writer.WriteComma();

            if (query.PageSizeSet && query.PageSize >= 0)
            {
                writer.WritePropertyName(nameof(query.PageSize));
                writer.WriteInteger(query.PageSize);
                writer.WriteComma();
            }

            if (query.WaitForNonStaleResults)
            {
                writer.WritePropertyName(nameof(query.WaitForNonStaleResults));
                writer.WriteBool(query.WaitForNonStaleResults);
                writer.WriteComma();
            }

            if (query.Start > 0)
            {
                writer.WritePropertyName(nameof(query.Start));
                writer.WriteInteger(query.Start);
                writer.WriteComma();
            }

            if (query.WaitForNonStaleResultsTimeout.HasValue)
            {
                writer.WritePropertyName(nameof(query.WaitForNonStaleResultsTimeout));
                writer.WriteString(query.WaitForNonStaleResultsTimeout.Value.ToInvariantString());
                writer.WriteComma();
            }

            if (query.DisableCaching)
            {
                writer.WritePropertyName(nameof(query.DisableCaching));
                writer.WriteBool(query.DisableCaching);
                writer.WriteComma();
            }

#if FEATURE_EXPLAIN_SCORES
            if (query.ExplainScores)
            {
                writer.WritePropertyName(nameof(query.ExplainScores));
                writer.WriteBool(query.ExplainScores);
                writer.WriteComma();
            }
#endif

#if FEATURE_SHOW_TIMINGS
            if (query.ShowTimings)
            {
                writer.WritePropertyName(nameof(query.ShowTimings));
                writer.WriteBool(query.ShowTimings);
                writer.WriteComma();
            }
#endif

            if (query.SkipDuplicateChecking)
            {
                writer.WritePropertyName(nameof(query.SkipDuplicateChecking));
                writer.WriteBool(query.SkipDuplicateChecking);
                writer.WriteComma();
            }

            writer.WritePropertyName(nameof(query.QueryParameters));
            if (query.QueryParameters != null)
            {
                writer.WriteObject(EntityToBlittable.ConvertCommandToBlittable(query.QueryParameters, context));
            }
            else
            {
                writer.WriteNull();
            }

            writer.WriteEndObject();
        }
예제 #26
0
        private async Task RequestHandler(HttpContext context)
        {
            string database = null;

            try
            {
                context.Response.StatusCode = (int)HttpStatusCode.OK;
                context.Response.Headers["Content-Type"] = "application/json; charset=utf-8";

                var sp = Stopwatch.StartNew();
                database = await _router.HandlePath(context, context.Request.Method, context.Request.Path.Value);

                sp.Stop();

                if (_logger.IsInfoEnabled && SkipHttpLogging == false)
                {
                    _logger.Info($"{context.Request.Method} {context.Request.Path.Value}?{context.Request.QueryString.Value} - {context.Response.StatusCode} - {sp.ElapsedMilliseconds:#,#;;0} ms");
                }

                if (TrafficWatchManager.HasRegisteredClients)
                {
                    LogTrafficWatch(context, sp.ElapsedMilliseconds, database);
                }
            }
            catch (Exception e)
            {
                if (TrafficWatchManager.HasRegisteredClients)
                {
                    LogTrafficWatch(context, 0, database ?? "N/A");
                }

                if (context.RequestAborted.IsCancellationRequested)
                {
                    return;
                }

                //TODO: special handling for argument exception (400 bad request)
                //TODO: operation canceled (timeout)
                //TODO: Invalid data exception 422

                //TODO: Proper json output, not like this
                MaybeSetExceptionStatusCode(context, e);

                using (_server.ServerStore.ContextPool.AllocateOperationContext(out JsonOperationContext ctx))
                {
                    var djv = new DynamicJsonValue
                    {
                        [nameof(ExceptionDispatcher.ExceptionSchema.Url)]     = $"{context.Request.Path}{context.Request.QueryString}",
                        [nameof(ExceptionDispatcher.ExceptionSchema.Type)]    = e.GetType().FullName,
                        [nameof(ExceptionDispatcher.ExceptionSchema.Message)] = e.Message
                    };


#if EXCEPTION_ERROR_HUNT
                    var f = Guid.NewGuid() + ".error";
                    File.WriteAllText(f,
                                      $"{context.Request.Path}{context.Request.QueryString}" + Environment.NewLine + errorString);
#endif
                    djv[nameof(ExceptionDispatcher.ExceptionSchema.Error)] = e.ToString();

                    MaybeAddAdditionalExceptionData(djv, e);


                    var response = context.Response;

                    using (var writer = new BlittableJsonTextWriter(ctx, response.Body))
                    {
                        var json = ctx.ReadObject(djv, "exception");
                        writer.WriteObject(json);
                    }

#if EXCEPTION_ERROR_HUNT
                    File.Delete(f);
#endif
                }
            }
        }
예제 #27
0
        public async Task Patch()
        {
            var id = GetQueryStringValueAndAssertIfSingleAndNotEmpty("id");

            var isTest    = GetBoolValueQueryString("test", required: false) ?? false;
            var debugMode = GetBoolValueQueryString("debug", required: false) ?? isTest;
            var skipPatchIfChangeVectorMismatch = GetBoolValueQueryString("skipPatchIfChangeVectorMismatch", required: false) ?? false;

            using (ContextPool.AllocateOperationContext(out DocumentsOperationContext context))
            {
                var request = context.Read(RequestBodyStream(), "ScriptedPatchRequest");
                if (request.TryGet("Patch", out BlittableJsonReaderObject patchCmd) == false || patchCmd == null)
                {
                    throw new ArgumentException("The 'Patch' field in the body request is mandatory");
                }

                var patch = PatchRequest.Parse(patchCmd, out var patchArgs);

                PatchRequest patchIfMissing = null;
                BlittableJsonReaderObject patchIfMissingArgs = null;
                if (request.TryGet("PatchIfMissing", out BlittableJsonReaderObject patchIfMissingCmd) && patchIfMissingCmd != null)
                {
                    patchIfMissing = PatchRequest.Parse(patchIfMissingCmd, out patchIfMissingArgs);
                }

                var changeVector = context.GetLazyString(GetStringFromHeaders("If-Match"));

                var command = new PatchDocumentCommand(context,
                                                       id,
                                                       changeVector,
                                                       skipPatchIfChangeVectorMismatch,
                                                       (patch, patchArgs),
                                                       (patchIfMissing, patchIfMissingArgs),
                                                       Database,
                                                       isTest,
                                                       debugMode,
                                                       true,
                                                       returnDocument: false
                                                       );


                if (isTest == false)
                {
                    await Database.TxMerger.Enqueue(command);
                }
                else
                {
                    // PutDocument requires the write access to the docs storage
                    // testing patching is rare enough not to optimize it
                    using (context.OpenWriteTransaction())
                    {
                        command.Execute(context, null);
                    }
                }

                switch (command.PatchResult.Status)
                {
                case PatchStatus.DocumentDoesNotExist:
                    HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
                    return;

                case PatchStatus.Created:
                    HttpContext.Response.StatusCode = (int)HttpStatusCode.Created;
                    break;

                case PatchStatus.Skipped:
                    HttpContext.Response.StatusCode = (int)HttpStatusCode.NotModified;
                    return;

                case PatchStatus.Patched:
                case PatchStatus.NotModified:
                    HttpContext.Response.StatusCode = (int)HttpStatusCode.OK;
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream()))
                {
                    writer.WriteStartObject();

                    writer.WritePropertyName(nameof(command.PatchResult.Status));
                    writer.WriteString(command.PatchResult.Status.ToString());
                    writer.WriteComma();

                    writer.WritePropertyName(nameof(command.PatchResult.ModifiedDocument));
                    writer.WriteObject(command.PatchResult.ModifiedDocument);

                    if (debugMode)
                    {
                        writer.WriteComma();
                        writer.WritePropertyName(nameof(command.PatchResult.OriginalDocument));
                        if (isTest)
                        {
                            writer.WriteObject(command.PatchResult.OriginalDocument);
                        }
                        else
                        {
                            writer.WriteNull();
                        }

                        writer.WriteComma();

                        writer.WritePropertyName(nameof(command.PatchResult.Debug));

                        context.Write(writer, new DynamicJsonValue
                        {
                            ["Info"]    = new DynamicJsonArray(command.DebugOutput),
                            ["Actions"] = command.DebugActions
                        });
                    }

                    switch (command.PatchResult.Status)
                    {
                    case PatchStatus.Created:
                    case PatchStatus.Patched:

                        writer.WriteComma();

                        writer.WritePropertyName(nameof(command.PatchResult.LastModified));
                        writer.WriteString(command.PatchResult.LastModified.GetDefaultRavenFormat(isUtc: command.PatchResult.LastModified.Kind == DateTimeKind.Utc));
                        writer.WriteComma();

                        writer.WritePropertyName(nameof(command.PatchResult.ChangeVector));
                        writer.WriteString(command.PatchResult.ChangeVector);
                        writer.WriteComma();

                        writer.WritePropertyName(nameof(command.PatchResult.Collection));
                        writer.WriteString(command.PatchResult.Collection);
                        break;
                    }

                    writer.WriteEndObject();
                }
            }
        }
예제 #28
0
        private async Task RequestHandler(HttpContext context)
        {
            var requestHandlerContext = new RequestHandlerContext
            {
                HttpContext = context
            };
            Exception exception = null;
            Stopwatch sp        = null;

            try
            {
                context.Response.StatusCode = (int)HttpStatusCode.OK;
                context.Response.Headers["Content-Type"] = "application/json; charset=utf-8";
                context.Response.Headers[Constants.Headers.ServerVersion] = RavenVersionAttribute.Instance.AssemblyVersion;

                if (_server.ServerStore.Initialized == false)
                {
                    await _server.ServerStore.InitializationCompleted.WaitAsync();
                }

                sp = Stopwatch.StartNew();
                await _router.HandlePath(requestHandlerContext);

                sp.Stop();
            }
            catch (Exception e)
            {
                sp?.Stop();
                exception = e;

                CheckVersionAndWrapException(context, ref e);

                MaybeSetExceptionStatusCode(context, _server.ServerStore, e);

                if (context.RequestAborted.IsCancellationRequested)
                {
                    return;
                }

                using (_server.ServerStore.ContextPool.AllocateOperationContext(out JsonOperationContext ctx))
                {
                    var djv = new DynamicJsonValue
                    {
                        [nameof(ExceptionDispatcher.ExceptionSchema.Url)]     = $"{context.Request.Path}{context.Request.QueryString}",
                        [nameof(ExceptionDispatcher.ExceptionSchema.Type)]    = e.GetType().FullName,
                        [nameof(ExceptionDispatcher.ExceptionSchema.Message)] = e.Message,
                        [nameof(ExceptionDispatcher.ExceptionSchema.Error)]   = e.ToString()
                    };

#if EXCEPTION_ERROR_HUNT
                    var f = Guid.NewGuid() + ".error";
                    File.WriteAllText(f,
                                      $"{context.Request.Path}{context.Request.QueryString}" + Environment.NewLine + errorString);
#endif

                    MaybeAddAdditionalExceptionData(djv, e);

                    using (var writer = new BlittableJsonTextWriter(ctx, context.Response.Body))
                    {
                        var json = ctx.ReadObject(djv, "exception");
                        writer.WriteObject(json);
                    }

#if EXCEPTION_ERROR_HUNT
                    File.Delete(f);
#endif
                }
            }
            finally
            {
                // check if TW has clients
                if (TrafficWatchManager.HasRegisteredClients)
                {
                    var database = requestHandlerContext.Database?.Name;
                    LogTrafficWatch(context, sp?.ElapsedMilliseconds ?? 0, database);
                }

                if (sp != null && requestHandlerContext.HttpContext.Response.StatusCode != (int)HttpStatusCode.SwitchingProtocols) // exclude web sockets
                {
                    var requestDuration = sp.ElapsedMilliseconds;
                    requestHandlerContext.RavenServer?.Metrics.Requests.UpdateDuration(requestDuration);
                    requestHandlerContext.Database?.Metrics.Requests.UpdateDuration(requestDuration);
                }

                if (_logger.IsInfoEnabled && SkipHttpLogging == false)
                {
                    _logger.Info($"{context.Request.Method} {context.Request.Path.Value}{context.Request.QueryString.Value} - {context.Response.StatusCode} - {(sp?.ElapsedMilliseconds ?? 0):#,#;;0} ms", exception);
                }
            }
        }
예제 #29
0
        public async Task Try()
        {
            using (ContextPool.AllocateOperationContext(out DocumentsOperationContext context))
            {
                var json = await context.ReadForMemoryAsync(RequestBodyStream(), null);

                var tryout = JsonDeserializationServer.SubscriptionTryout(json);

                var(collection, (script, functions), revisions) = SubscriptionConnection.ParseSubscriptionQuery(tryout.Query);
                SubscriptionPatchDocument patch = null;
                if (string.IsNullOrEmpty(script) == false)
                {
                    patch = new SubscriptionPatchDocument(script, functions);
                }

                if (collection == null)
                {
                    throw new ArgumentException("Collection must be specified");
                }

                var pageSize = GetIntValueQueryString("pageSize") ?? 1;

                var state = new SubscriptionState
                {
                    ChangeVectorForNextBatchStartingPoint = tryout.ChangeVector,
                    Query = tryout.Query
                };

                var fetcher = new SubscriptionDocumentsFetcher(Database, pageSize, -0x42,
                                                               new IPEndPoint(HttpContext.Connection.RemoteIpAddress, HttpContext.Connection.RemotePort), collection, revisions, state, patch);

                if (Enum.TryParse(
                        tryout.ChangeVector,
                        out Constants.Documents.SubscriptionChangeVectorSpecialStates changeVectorSpecialValue))
                {
                    switch (changeVectorSpecialValue)
                    {
                    case Constants.Documents.SubscriptionChangeVectorSpecialStates.BeginningOfTime:
                    case Constants.Documents.SubscriptionChangeVectorSpecialStates.DoNotChange:
                        state.ChangeVectorForNextBatchStartingPoint = null;
                        break;

                    case Constants.Documents.SubscriptionChangeVectorSpecialStates.LastDocument:
                        state.ChangeVectorForNextBatchStartingPoint = Database.DocumentsStorage.GetLastDocumentChangeVector(context, collection);
                        break;
                    }
                }

                using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream()))
                {
                    writer.WriteStartObject();
                    writer.WritePropertyName("Results");
                    writer.WriteStartArray();

                    using (context.OpenReadTransaction())
                    {
                        var first = true;

                        foreach (var itemDetails in fetcher.GetDataToSend(context, 0))
                        {
                            if (itemDetails.Doc.Data == null)
                            {
                                continue;
                            }

                            if (first == false)
                            {
                                writer.WriteComma();
                            }

                            if (itemDetails.Exception == null)
                            {
                                writer.WriteDocument(context, itemDetails.Doc, metadataOnly: false);
                            }
                            else
                            {
                                var docWithExcepton = new DocumentWithException
                                {
                                    Exception    = itemDetails.Exception.ToString(),
                                    ChangeVector = itemDetails.Doc.ChangeVector,
                                    Id           = itemDetails.Doc.Id,
                                    DocumentData = itemDetails.Doc.Data
                                };
                                writer.WriteObject(context.ReadObject(docWithExcepton.ToJson(), ""));
                            }

                            first = false;
                        }
                    }

                    writer.WriteEndArray();
                    writer.WriteEndObject();
                }
            }
        }
예제 #30
0
        public async Task Try()
        {
            using (ContextPool.AllocateOperationContext(out DocumentsOperationContext context))
            {
                BlittableJsonReaderObject json = await context.ReadForMemoryAsync(RequestBodyStream(), null);

                SubscriptionTryout tryout = JsonDeserializationServer.SubscriptionTryout(json);

                SubscriptionConnection.ParsedSubscription sub = SubscriptionConnection.ParseSubscriptionQuery(tryout.Query);
                SubscriptionPatchDocument patch = null;
                if (string.IsNullOrEmpty(sub.Script) == false)
                {
                    patch = new SubscriptionPatchDocument(sub.Script, sub.Functions);
                }

                if (sub.Collection == null)
                {
                    throw new ArgumentException("Collection must be specified");
                }

                const int maxPageSize = 1024;
                var       pageSize    = GetIntValueQueryString("pageSize") ?? 1;
                if (pageSize > maxPageSize)
                {
                    throw new ArgumentException($"Cannot gather more than {maxPageSize} results during tryouts, but requested number was {pageSize}.");
                }

                var state = new SubscriptionState
                {
                    ChangeVectorForNextBatchStartingPoint = tryout.ChangeVector,
                    Query = tryout.Query
                };

                var fetcher = new SubscriptionDocumentsFetcher(Database, int.MaxValue, -0x42,
                                                               new IPEndPoint(HttpContext.Connection.RemoteIpAddress, HttpContext.Connection.RemotePort), sub.Collection, sub.Revisions, state, patch);

                var includeCmd = new IncludeDocumentsCommand(Database.DocumentsStorage, context, sub.Includes, isProjection: patch != null);

                if (Enum.TryParse(
                        tryout.ChangeVector,
                        out Constants.Documents.SubscriptionChangeVectorSpecialStates changeVectorSpecialValue))
                {
                    switch (changeVectorSpecialValue)
                    {
                    case Constants.Documents.SubscriptionChangeVectorSpecialStates.BeginningOfTime:
                    case Constants.Documents.SubscriptionChangeVectorSpecialStates.DoNotChange:
                        state.ChangeVectorForNextBatchStartingPoint = null;
                        break;

                    case Constants.Documents.SubscriptionChangeVectorSpecialStates.LastDocument:
                        using (context.OpenReadTransaction())
                        {
                            state.ChangeVectorForNextBatchStartingPoint = Database.DocumentsStorage.GetLastDocumentChangeVector(context.Transaction.InnerTransaction, context, sub.Collection);
                        }
                        break;
                    }
                }
                else
                {
                    state.ChangeVectorForNextBatchStartingPoint = tryout.ChangeVector;
                }

                var changeVector = state.ChangeVectorForNextBatchStartingPoint.ToChangeVector();
                var cv           = changeVector.FirstOrDefault(x => x.DbId == Database.DbBase64Id);

                var sp        = Stopwatch.StartNew();
                var timeLimit = TimeSpan.FromSeconds(GetIntValueQueryString("timeLimit", false) ?? 15);
                var startEtag = cv.Etag;

                using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream()))
                    using (context.OpenReadTransaction())
                    {
                        writer.WriteStartObject();
                        writer.WritePropertyName("Results");
                        writer.WriteStartArray();
                        var numberOfDocs = 0;
                        while (numberOfDocs == 0 && sp.Elapsed < timeLimit)
                        {
                            var first    = true;
                            var lastEtag = startEtag;
                            foreach (var itemDetails in fetcher.GetDataToSend(context, includeCmd, startEtag))
                            {
                                if (itemDetails.Doc.Data != null)
                                {
                                    using (itemDetails.Doc.Data)
                                    {
                                        includeCmd.Gather(itemDetails.Doc);

                                        if (first == false)
                                        {
                                            writer.WriteComma();
                                        }

                                        if (itemDetails.Exception == null)
                                        {
                                            writer.WriteDocument(context, itemDetails.Doc, metadataOnly: false);
                                        }
                                        else
                                        {
                                            var documentWithException = new DocumentWithException
                                            {
                                                Exception    = itemDetails.Exception.ToString(),
                                                ChangeVector = itemDetails.Doc.ChangeVector,
                                                Id           = itemDetails.Doc.Id,
                                                DocumentData = itemDetails.Doc.Data
                                            };
                                            writer.WriteObject(context.ReadObject(documentWithException.ToJson(), ""));
                                        }

                                        first = false;

                                        if (++numberOfDocs >= pageSize)
                                        {
                                            break;
                                        }
                                    }
                                }

                                if (sp.Elapsed >= timeLimit)
                                {
                                    break;
                                }

                                lastEtag = itemDetails.Doc.Etag;
                            }

                            if (startEtag == lastEtag)
                            {
                                break;
                            }

                            startEtag = lastEtag;
                        }

                        writer.WriteEndArray();
                        writer.WriteComma();
                        writer.WritePropertyName("Includes");
                        var includes = new List <Document>();
                        includeCmd.Fill(includes);
                        writer.WriteIncludes(context, includes);
                        writer.WriteEndObject();
                    }
            }
        }