diff --git a/global.json b/global.json
index 72d38cd..60b4c02 100644
--- a/global.json
+++ b/global.json
@@ -1,7 +1,7 @@
{
"sdk": {
"version": "8.0.100",
- "rollForward": "latestMajor",
+ "rollForward": "latestMinor",
"allowPrerelease": false
}
}
\ No newline at end of file
diff --git a/src/Elastic.Transport/Components/Pipeline/RequestData.cs b/src/Elastic.Transport/Components/Pipeline/RequestData.cs
index eeb44c8..f8a7b2b 100644
--- a/src/Elastic.Transport/Components/Pipeline/RequestData.cs
+++ b/src/Elastic.Transport/Components/Pipeline/RequestData.cs
@@ -7,7 +7,6 @@
using System.Collections.Specialized;
using System.Security.Cryptography.X509Certificates;
using Elastic.Transport.Extensions;
-using Elastic.Transport.Products;
namespace Elastic.Transport;
@@ -41,9 +40,6 @@ public RequestData(ITransportConfiguration global, IRequestConfiguration? local
ProxyPassword = global.ProxyPassword;
DisableAutomaticProxyDetection = global.DisableAutomaticProxyDetection;
UserAgent = global.UserAgent;
- ResponseBuilders = global.ResponseBuilders;
- ProductResponseBuilders = global.ProductRegistration.ResponseBuilders;
-
KeepAliveInterval = (int)(global.KeepAliveInterval?.TotalMilliseconds ?? 2000);
KeepAliveTime = (int)(global.KeepAliveTime?.TotalMilliseconds ?? 2000);
RunAs = local?.RunAs ?? global.RunAs;
@@ -90,13 +86,36 @@ public RequestData(ITransportConfiguration global, IRequestConfiguration? local
Headers ??= [];
Headers.Add(OpaqueIdHeader, local.OpaqueId);
}
- }
- ///
- public IReadOnlyCollection ProductResponseBuilders { get; }
+ // If there are builders set at the transport level and on the request config, we combine them,
+ // prioritising the request config response builders as most specific.
+ if (local is not null && local.ResponseBuilders.Count > 0 && global.ResponseBuilders.Count > 0)
+ {
+ var builders = new IResponseBuilder[local.ResponseBuilders.Count + global.ResponseBuilders.Count];
- ///
- public IReadOnlyCollection ResponseBuilders { get; }
+ var counter = 0;
+ foreach (var builder in local.ResponseBuilders)
+ {
+ builders[counter++] = builder;
+ }
+ foreach (var builder in global.ResponseBuilders)
+ {
+ builders[counter++] = builder;
+ }
+
+ ResponseBuilders = builders;
+ }
+ else if (local is not null && local.ResponseBuilders.Count > 0)
+ {
+ ResponseBuilders = local.ResponseBuilders;
+ }
+ else
+ {
+ ResponseBuilders = global.ResponseBuilders;
+ }
+
+ ProductResponseBuilders = global.ProductRegistration.ResponseBuilders;
+ }
///
public MemoryStreamFactory MemoryStreamFactory { get; }
@@ -168,4 +187,8 @@ public RequestData(ITransportConfiguration global, IRequestConfiguration? local
public bool DisableSniff { get; }
///
public bool DisablePings { get; }
+ ///
+ public IReadOnlyCollection ProductResponseBuilders { get; }
+ ///
+ public IReadOnlyCollection ResponseBuilders { get; }
}
diff --git a/src/Elastic.Transport/Components/TransportClient/HttpRequestInvoker.cs b/src/Elastic.Transport/Components/TransportClient/HttpRequestInvoker.cs
index afb6023..5223ba0 100644
--- a/src/Elastic.Transport/Components/TransportClient/HttpRequestInvoker.cs
+++ b/src/Elastic.Transport/Components/TransportClient/HttpRequestInvoker.cs
@@ -199,8 +199,8 @@ private async ValueTask RequestCoreAsync(bool isAsync, End
}
else
{
- responseStream.Dispose();
- receivedResponse.Dispose();
+ responseStream?.Dispose();
+ receivedResponse?.Dispose();
}
if (!OpenTelemetry.CurrentSpanIsElasticTransportOwnedAndHasListeners || (!(Activity.Current?.IsAllDataRequested ?? false)))
@@ -218,8 +218,8 @@ private async ValueTask RequestCoreAsync(bool isAsync, End
catch
{
// if there's an exception, ensure we always release the stream and response so that the connection is freed.
- responseStream.Dispose();
- receivedResponse.Dispose();
+ responseStream?.Dispose();
+ receivedResponse?.Dispose();
throw;
}
}
diff --git a/src/Elastic.Transport/Components/TransportClient/HttpWebRequestInvoker.cs b/src/Elastic.Transport/Components/TransportClient/HttpWebRequestInvoker.cs
index dd97e3c..8db2c22 100644
--- a/src/Elastic.Transport/Components/TransportClient/HttpWebRequestInvoker.cs
+++ b/src/Elastic.Transport/Components/TransportClient/HttpWebRequestInvoker.cs
@@ -190,8 +190,8 @@ private async ValueTask RequestCoreAsync(bool isAsync, End
}
else
{
- responseStream.Dispose();
- receivedResponse.Dispose();
+ responseStream?.Dispose();
+ receivedResponse?.Dispose();
}
if (OpenTelemetry.CurrentSpanIsElasticTransportOwnedAndHasListeners && (Activity.Current?.IsAllDataRequested ?? false))
@@ -208,8 +208,8 @@ private async ValueTask RequestCoreAsync(bool isAsync, End
catch
{
// if there's an exception, ensure we always release the stream and response so that the connection is freed.
- responseStream.Dispose();
- receivedResponse.Dispose();
+ responseStream?.Dispose();
+ receivedResponse?.Dispose();
throw;
}
}
diff --git a/src/Elastic.Transport/Configuration/IRequestConfiguration.cs b/src/Elastic.Transport/Configuration/IRequestConfiguration.cs
new file mode 100644
index 0000000..39934db
--- /dev/null
+++ b/src/Elastic.Transport/Configuration/IRequestConfiguration.cs
@@ -0,0 +1,155 @@
+// Licensed to Elasticsearch B.V under one or more agreements.
+// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
+// See the LICENSE file in the project root for more information
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Security.Cryptography.X509Certificates;
+
+namespace Elastic.Transport;
+
+///
+/// Allows you to inject per request overrides to the current .
+///
+public interface IRequestConfiguration
+{
+ ///
+ /// Force a different Accept header on the request
+ ///
+ string? Accept { get; }
+
+ ///
+ /// Treat the following statuses (on top of the 200 range) NOT as error.
+ ///
+ IReadOnlyCollection? AllowedStatusCodes { get; }
+
+ /// Provide an authentication header override for this request
+ AuthorizationHeader? Authentication { get; }
+
+ ///
+ /// Use the following client certificates to authenticate this single request
+ ///
+ X509CertificateCollection? ClientCertificates { get; }
+
+ ///
+ /// Force a different Content-Type header on the request
+ ///
+ string? ContentType { get; }
+
+ ///
+ /// Whether to buffer the request and response bytes for the call
+ ///
+ bool? DisableDirectStreaming { get; }
+
+ ///
+ /// Whether to disable the audit trail for the request.
+ ///
+ bool? DisableAuditTrail { get; }
+
+ ///
+ /// Under no circumstance do a ping before the actual call. If a node was previously dead a small ping with
+ /// low connect timeout will be tried first in normal circumstances
+ ///
+ bool? DisablePings { get; }
+
+ ///
+ /// Forces no sniffing to occur on the request no matter what configuration is in place
+ /// globally
+ ///
+ bool? DisableSniff { get; }
+
+ ///
+ /// Whether or not this request should be pipelined. http://en.wikipedia.org/wiki/HTTP_pipelining defaults to true
+ ///
+ bool? HttpPipeliningEnabled { get; }
+
+ ///
+ /// Enable gzip compressed requests and responses
+ ///
+ bool? EnableHttpCompression { get; }
+
+ ///
+ /// This will force the operation on the specified node, this will bypass any configured connection pool and will no retry.
+ ///
+ Uri? ForceNode { get; }
+
+ ///
+ /// When a retryable exception occurs or status code is returned this controls the maximum
+ /// amount of times we should retry the call to Elasticsearch
+ ///
+ int? MaxRetries { get; }
+
+ ///
+ /// Limits the total runtime including retries separately from
+ ///
+ /// When not specified defaults to which itself defaults to 60 seconds
+ ///
+ ///
+ TimeSpan? MaxRetryTimeout { get; }
+
+ ///
+ /// Associate an Id with this user-initiated task, such that it can be located in the cluster task list.
+ /// Valid only for Elasticsearch 6.2.0+
+ ///
+ string? OpaqueId { get; }
+
+ /// Determines whether to parse all HTTP headers in the request.
+ bool? ParseAllHeaders { get; }
+
+ ///
+ /// The ping timeout for this specific request
+ ///
+ TimeSpan? PingTimeout { get; }
+
+ ///
+ /// The timeout for this specific request, takes precedence over the global timeout init
+ ///
+ TimeSpan? RequestTimeout { get; }
+
+ ///
+ /// Additional response builders to apply.
+ ///
+ IReadOnlyCollection ResponseBuilders { get; }
+
+ /// Specifies the headers from the response that should be parsed.
+ HeadersList? ResponseHeadersToParse { get; }
+
+ ///
+ /// Submit the request on behalf in the context of a different shield user
+ /// https://www.elastic.co/guide/en/shield/current/submitting-requests-for-other-users.html
+ ///
+ string? RunAs { get; }
+
+ ///
+ /// Instead of following a c/go like error checking on response.IsValid do throw an exception (except when is false)
+ /// on the client when a call resulted in an exception on either the client or the Elasticsearch server.
+ /// Reasons for such exceptions could be search parser errors, index missing exceptions, etc...
+ ///
+ bool? ThrowExceptions { get; }
+
+ ///
+ /// Whether the request should be sent with chunked Transfer-Encoding.
+ ///
+ bool? TransferEncodingChunked { get; }
+
+ ///
+ /// Try to send these headers for this single request
+ ///
+ NameValueCollection? Headers { get; }
+
+ ///
+ /// Enable statistics about TCP connections to be collected when making a request
+ ///
+ bool? EnableTcpStats { get; }
+
+ ///
+ /// Enable statistics about thread pools to be collected when making a request
+ ///
+ bool? EnableThreadPoolStats { get; }
+
+ ///
+ /// Holds additional meta data about the request.
+ ///
+ RequestMetaData? RequestMetaData { get; }
+}
diff --git a/src/Elastic.Transport/Configuration/ITransportConfiguration.cs b/src/Elastic.Transport/Configuration/ITransportConfiguration.cs
index 4cc35cc..4fc8c0d 100644
--- a/src/Elastic.Transport/Configuration/ITransportConfiguration.cs
+++ b/src/Elastic.Transport/Configuration/ITransportConfiguration.cs
@@ -210,9 +210,4 @@ public interface ITransportConfiguration : IRequestConfiguration, IDisposable
/// about the client and runtime.
///
bool DisableMetaHeader { get; }
-
- ///
- /// Additional response builders to apply.
- ///
- IReadOnlyCollection ResponseBuilders { get; }
}
diff --git a/src/Elastic.Transport/Configuration/RequestConfiguration.cs b/src/Elastic.Transport/Configuration/RequestConfiguration.cs
index 8506fef..940d69b 100644
--- a/src/Elastic.Transport/Configuration/RequestConfiguration.cs
+++ b/src/Elastic.Transport/Configuration/RequestConfiguration.cs
@@ -11,146 +11,6 @@
namespace Elastic.Transport;
-///
-/// Allows you to inject per request overrides to the current .
-///
-public interface IRequestConfiguration
-{
- ///
- /// Force a different Accept header on the request
- ///
- string? Accept { get; }
-
- ///
- /// Treat the following statuses (on top of the 200 range) NOT as error.
- ///
- IReadOnlyCollection? AllowedStatusCodes { get; }
-
- /// Provide an authentication header override for this request
- AuthorizationHeader? Authentication { get; }
-
- ///
- /// Use the following client certificates to authenticate this single request
- ///
- X509CertificateCollection? ClientCertificates { get; }
-
- ///
- /// Force a different Content-Type header on the request
- ///
- string? ContentType { get; }
-
- ///
- /// Whether to buffer the request and response bytes for the call
- ///
- bool? DisableDirectStreaming { get; }
-
- ///
- /// Whether to disable the audit trail for the request.
- ///
- bool? DisableAuditTrail { get; }
-
- ///
- /// Under no circumstance do a ping before the actual call. If a node was previously dead a small ping with
- /// low connect timeout will be tried first in normal circumstances
- ///
- bool? DisablePings { get; }
-
- ///
- /// Forces no sniffing to occur on the request no matter what configuration is in place
- /// globally
- ///
- bool? DisableSniff { get; }
-
- ///
- /// Whether or not this request should be pipelined. http://en.wikipedia.org/wiki/HTTP_pipelining defaults to true
- ///
- bool? HttpPipeliningEnabled { get; }
-
- ///
- /// Enable gzip compressed requests and responses
- ///
- bool? EnableHttpCompression { get; }
-
- ///
- /// This will force the operation on the specified node, this will bypass any configured connection pool and will no retry.
- ///
- Uri? ForceNode { get; }
-
- ///
- /// When a retryable exception occurs or status code is returned this controls the maximum
- /// amount of times we should retry the call to Elasticsearch
- ///
- int? MaxRetries { get; }
-
- ///
- /// Limits the total runtime including retries separately from
- ///
- /// When not specified defaults to which itself defaults to 60 seconds
- ///