Skip to content

Commit 6ee869f

Browse files
russcamMpdreamz
authored andcommitted
Return default when no bytes read from response streaming-no-response… (#3882)
* Return default when no bytes read from response streaming-no-response-body This commit returns default(T) when no bytes are read from the response stream. Move the stream null and seek check into JsonSerializer. Update index exists integration test to not disable direct streaming in order to test. * Changed formatting to indented * do not disable direct streaming
1 parent 2c8ff4b commit 6ee869f

File tree

6 files changed

+76
-62
lines changed

6 files changed

+76
-62
lines changed

src/Elasticsearch.Net/Serialization/LowLevelRequestResponseSerializer.cs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,21 @@ public class LowLevelRequestResponseSerializer : IElasticsearchSerializer
1313

1414
public object Deserialize(Type type, Stream stream)
1515
{
16-
if (stream == null || stream.CanSeek && stream.Length == 0) return Task.FromResult(type.DefaultValue());
17-
1816
return JsonSerializer.NonGeneric.Deserialize(type, stream, ElasticsearchNetFormatterResolver.Instance);
1917
}
2018

2119
public T Deserialize<T>(Stream stream)
2220
{
23-
if (stream == null || stream.CanSeek && stream.Length == 0) return default(T);
24-
2521
return JsonSerializer.Deserialize<T>(stream, ElasticsearchNetFormatterResolver.Instance);
2622
}
2723

2824
public Task<object> DeserializeAsync(Type type, Stream stream, CancellationToken cancellationToken = default)
2925
{
30-
if (stream == null || stream.CanSeek && stream.Length == 0) return Task.FromResult(type.DefaultValue());
31-
3226
return JsonSerializer.NonGeneric.DeserializeAsync(type, stream, ElasticsearchNetFormatterResolver.Instance);
3327
}
3428

3529
public Task<T> DeserializeAsync<T>(Stream stream, CancellationToken cancellationToken = default)
3630
{
37-
if (stream == null || stream.CanSeek && stream.Length == 0) return Task.FromResult(default(T));
38-
3931
return JsonSerializer.DeserializeAsync<T>(stream, ElasticsearchNetFormatterResolver.Instance);
4032
}
4133

src/Elasticsearch.Net/Utf8Json/JsonSerializer.cs

Lines changed: 60 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
using System.IO;
2727
using System.Linq;
2828
using System.Text;
29+
using System.Threading.Tasks;
2930
using Elasticsearch.Net.Utf8Json.Internal;
3031
using Elasticsearch.Net.Utf8Json.Resolvers;
3132

@@ -254,7 +255,11 @@ public static T Deserialize<T>(byte[] bytes, int offset)
254255

255256
public static T Deserialize<T>(byte[] bytes, int offset, IJsonFormatterResolver resolver)
256257
{
257-
if (resolver == null) resolver = DefaultResolver;
258+
if (bytes == null || bytes.Length == 0)
259+
return default;
260+
261+
if (resolver == null)
262+
resolver = DefaultResolver;
258263

259264
var reader = new JsonReader(bytes, offset);
260265
var formatter = resolver.GetFormatterWithVerify<T>();
@@ -281,11 +286,14 @@ public static T Deserialize<T>(Stream stream)
281286

282287
public static T Deserialize<T>(Stream stream, IJsonFormatterResolver resolver)
283288
{
284-
if (resolver == null) resolver = DefaultResolver;
289+
if (stream == null || stream.CanSeek && stream.Length == 0)
290+
return default;
291+
292+
if (resolver == null)
293+
resolver = DefaultResolver;
285294

286295
#if NETSTANDARD && !NET45
287-
var ms = stream as MemoryStream;
288-
if (ms != null)
296+
if (stream is MemoryStream ms)
289297
{
290298
if (ms.TryGetBuffer(out var buf2))
291299
{
@@ -302,39 +310,63 @@ public static T Deserialize<T>(Stream stream, IJsonFormatterResolver resolver)
302310
}
303311
}
304312
#endif
305-
{
306-
var buf = MemoryPool.Rent();
307-
var poolBuf = buf;
308-
try
309-
{
310-
var len = FillFromStream(stream, ref buf);
313+
var buf = MemoryPool.Rent();
314+
var poolBuf = buf;
315+
try
316+
{
317+
var length = FillFromStream(stream, ref buf);
311318

312-
// when token is number, can not use from pool(can not find end line).
313-
var token = new JsonReader(buf).GetCurrentJsonToken();
314-
if (token == JsonToken.Number)
315-
{
316-
buf = BinaryUtil.FastCloneWithResize(buf, len);
317-
}
319+
if (length == 0)
320+
return default;
318321

319-
return Deserialize<T>(buf, resolver);
320-
}
321-
finally
322+
// when token is number, can not use from pool(can not find end line).
323+
var token = new JsonReader(buf).GetCurrentJsonToken();
324+
if (token == JsonToken.Number)
322325
{
323-
MemoryPool.Return(poolBuf);
326+
buf = BinaryUtil.FastCloneWithResize(buf, length);
324327
}
325-
}
328+
329+
return Deserialize<T>(buf, resolver);
330+
}
331+
finally
332+
{
333+
MemoryPool.Return(poolBuf);
334+
}
326335
}
327336

328337
#if NETSTANDARD
329338

330-
public static System.Threading.Tasks.Task<T> DeserializeAsync<T>(Stream stream)
339+
public static Task<T> DeserializeAsync<T>(Stream stream)
331340
{
332341
return DeserializeAsync<T>(stream, defaultResolver);
333342
}
334343

335-
public static async System.Threading.Tasks.Task<T> DeserializeAsync<T>(Stream stream, IJsonFormatterResolver resolver)
344+
public static async Task<T> DeserializeAsync<T>(Stream stream, IJsonFormatterResolver resolver)
336345
{
337-
if (resolver == null) resolver = DefaultResolver;
346+
if (stream == null || stream.CanSeek && stream.Length == 0)
347+
return default;
348+
349+
if (resolver == null)
350+
resolver = DefaultResolver;
351+
352+
#if NETSTANDARD && !NET45
353+
if (stream is MemoryStream ms)
354+
{
355+
if (ms.TryGetBuffer(out var buf2))
356+
{
357+
// when token is number, can not use from pool(can not find end line).
358+
var token = new JsonReader(buf2.Array, buf2.Offset).GetCurrentJsonToken();
359+
if (token == JsonToken.Number)
360+
{
361+
var buf3 = new byte[buf2.Count];
362+
Buffer.BlockCopy(buf2.Array, buf2.Offset, buf3, 0, buf3.Length);
363+
return Deserialize<T>(buf3, 0, resolver);
364+
}
365+
366+
return Deserialize<T>(buf2.Array, buf2.Offset, resolver);
367+
}
368+
}
369+
#endif
338370

339371
var buffer = MemoryPool.Rent();
340372
var buf = buffer;
@@ -346,11 +378,12 @@ public static async System.Threading.Tasks.Task<T> DeserializeAsync<T>(Stream st
346378
{
347379
length += read;
348380
if (length == buf.Length)
349-
{
350-
BinaryUtil.FastResize(ref buf, length * 2);
351-
}
381+
BinaryUtil.FastResize(ref buf, length * 2);
352382
}
353383

384+
if (length == 0)
385+
return default;
386+
354387
// when token is number, can not use from pool(can not find end line).
355388
var token = new JsonReader(buf).GetCurrentJsonToken();
356389
if (token == JsonToken.Number)

src/Nest/CommonAbstractions/Extensions/TypeExtensions.cs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,6 @@ internal static object CreateInstance(this Type t, params object[] args)
6969
return activator(args);
7070
}
7171

72-
internal static object DefaultValue(this Type type) =>
73-
type.IsValueType
74-
? CachedDefaultValues.GetOrAdd(type, t =>
75-
Expression.Lambda<Func<object>>(
76-
Expression.Convert(Expression.Default(type), typeof(object))
77-
)
78-
.Compile()
79-
)
80-
.Invoke()
81-
: null;
82-
8372
//do not remove this is referenced through GetActivatorMethod
8473
internal static ObjectActivator<T> GetActivator<T>(ConstructorInfo ctor)
8574
{

src/Nest/CommonAbstractions/SerializationBehavior/DefaultHighLevelSerializer.cs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,36 +16,28 @@ internal class DefaultHighLevelSerializer : IElasticsearchSerializer, IInternalS
1616

1717
public T Deserialize<T>(Stream stream)
1818
{
19-
if (stream == null || stream.CanSeek && stream.Length == 0) return default;
20-
2119
return JsonSerializer.Deserialize<T>(stream, FormatterResolver);
2220
}
2321

2422
public object Deserialize(Type type, Stream stream)
2523
{
26-
if (stream == null || stream.CanSeek && stream.Length == 0) return type.DefaultValue();
27-
2824
return JsonSerializer.NonGeneric.Deserialize(type, stream, FormatterResolver);
2925
}
3026

3127
public Task<T> DeserializeAsync<T>(Stream stream, CancellationToken cancellationToken = default)
3228
{
33-
if (stream == null || stream.CanSeek && stream.Length == 0) return Task.FromResult(default(T));
34-
3529
return JsonSerializer.DeserializeAsync<T>(stream, FormatterResolver);
3630
}
3731

3832
public Task<object> DeserializeAsync(Type type, Stream stream, CancellationToken cancellationToken = default)
3933
{
40-
if (stream == null || stream.CanSeek && stream.Length == 0) return Task.FromResult(type.DefaultValue());
41-
4234
return JsonSerializer.NonGeneric.DeserializeAsync(type, stream, FormatterResolver);
4335
}
4436

45-
public virtual void Serialize<T>(T data, Stream writableStream, SerializationFormatting formatting = SerializationFormatting.Indented) =>
37+
public virtual void Serialize<T>(T data, Stream writableStream, SerializationFormatting formatting = SerializationFormatting.None) =>
4638
JsonSerializer.Serialize(writableStream, data, FormatterResolver);
4739

48-
public Task SerializeAsync<T>(T data, Stream stream, SerializationFormatting formatting = SerializationFormatting.Indented,
40+
public Task SerializeAsync<T>(T data, Stream stream, SerializationFormatting formatting = SerializationFormatting.None,
4941
CancellationToken cancellationToken = default
5042
) => JsonSerializer.SerializeAsync(stream, data, FormatterResolver);
5143
}

src/Tests/Tests.Core/ManagedElasticsearch/Clusters/ClientTestClusterBase.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ namespace Tests.Core.ManagedElasticsearch.Clusters
1313
{
1414
public abstract class ClientTestClusterBase : XunitClusterBase<ClientTestClusterConfiguration>, INestTestCluster
1515
{
16-
public ClientTestClusterBase() : this(new ClientTestClusterConfiguration()) { }
16+
protected ClientTestClusterBase() : this(new ClientTestClusterConfiguration()) { }
1717

18-
public ClientTestClusterBase(params ElasticsearchPlugin[] plugins) : this(new ClientTestClusterConfiguration(plugins)) { }
18+
protected ClientTestClusterBase(params ElasticsearchPlugin[] plugins) : this(new ClientTestClusterConfiguration(plugins)) { }
1919

20-
public ClientTestClusterBase(ClientTestClusterConfiguration configuration) : base(configuration) { }
20+
protected ClientTestClusterBase(ClientTestClusterConfiguration configuration) : base(configuration) { }
2121

2222
public IElasticClient Client => this.GetOrAddClient(s => ConnectionSettings(s.ApplyDomainSettings()));
2323

src/Tests/Tests/Indices/IndexManagement/IndicesExists/IndexExistsApiTests.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Elasticsearch.Net;
22
using FluentAssertions;
33
using Nest;
4+
using Tests.Core.Client.Settings;
45
using Tests.Core.ManagedElasticsearch.Clusters;
56
using Tests.Domain;
67
using Tests.Framework.EndpointTests;
@@ -31,6 +32,7 @@ protected override LazyResponses ClientUsage() => Calls(
3132
protected override void ExpectResponse(ExistsResponse response) => response.Exists.Should().BeTrue();
3233
}
3334

35+
// DisableDirectStreaming = false so that response stream is not seekable
3436
public class IndexNotExistsApiTests
3537
: ApiIntegrationTestBase<ReadOnlyCluster, ExistsResponse, IIndexExistsRequest, IndexExistsDescriptor, IndexExistsRequest>
3638
{
@@ -42,12 +44,18 @@ public IndexNotExistsApiTests(ReadOnlyCluster cluster, EndpointUsage usage) : ba
4244
protected override int ExpectStatusCode => 404;
4345
protected override HttpMethod HttpMethod => HttpMethod.HEAD;
4446

45-
protected override IndexExistsRequest Initializer => new IndexExistsRequest(NonExistentIndex);
47+
protected override IndexExistsRequest Initializer => new IndexExistsRequest(NonExistentIndex)
48+
{
49+
RequestConfiguration = new RequestConfiguration
50+
{
51+
DisableDirectStreaming = false
52+
}
53+
};
4654
protected override string UrlPath => $"/{NonExistentIndex}";
4755

4856
protected override LazyResponses ClientUsage() => Calls(
49-
(client, f) => client.Indices.Exists(NonExistentIndex),
50-
(client, f) => client.Indices.ExistsAsync(NonExistentIndex),
57+
(client, f) => client.Indices.Exists(NonExistentIndex, r => r.RequestConfiguration(c => c.DisableDirectStreaming(false))),
58+
(client, f) => client.Indices.ExistsAsync(NonExistentIndex,r => r.RequestConfiguration(c => c.DisableDirectStreaming(false))),
5159
(client, r) => client.Indices.Exists(r),
5260
(client, r) => client.Indices.ExistsAsync(r)
5361
);

0 commit comments

Comments
 (0)