in src/Elastic.Transport/Responses/DefaultResponseFactory.cs [35:122]
public override TResponse Create<TResponse>(
Endpoint endpoint,
BoundConfiguration boundConfiguration,
PostData? postData,
Exception? ex,
int? statusCode,
Dictionary<string, IEnumerable<string>>? headers,
Stream responseStream,
string? contentType,
long contentLength,
IReadOnlyDictionary<string, ThreadPoolStatistics>? threadPoolStats,
IReadOnlyDictionary<TcpState, int>? tcpStats) =>
CreateCoreAsync<TResponse>(false, endpoint, boundConfiguration, postData, ex, statusCode, headers, responseStream,
contentType, contentLength, threadPoolStats, tcpStats).EnsureCompleted();
/// <inheritdoc/>
public override Task<TResponse> CreateAsync<TResponse>(
Endpoint endpoint,
BoundConfiguration boundConfiguration,
PostData? postData,
Exception? ex,
int? statusCode,
Dictionary<string, IEnumerable<string>>? headers,
Stream responseStream,
string? contentType,
long contentLength,
IReadOnlyDictionary<string, ThreadPoolStatistics>? threadPoolStats,
IReadOnlyDictionary<TcpState, int>? tcpStats,
CancellationToken cancellationToken = default) =>
CreateCoreAsync<TResponse>(true, endpoint, boundConfiguration, postData, ex, statusCode, headers, responseStream,
contentType, contentLength, threadPoolStats, tcpStats, cancellationToken).AsTask();
private async ValueTask<TResponse> CreateCoreAsync<TResponse>(
bool isAsync,
Endpoint endpoint,
BoundConfiguration boundConfiguration,
PostData? postData,
Exception? ex,
int? statusCode,
Dictionary<string, IEnumerable<string>>? headers,
Stream responseStream,
string? contentType,
long contentLength,
IReadOnlyDictionary<string, ThreadPoolStatistics>? threadPoolStats,
IReadOnlyDictionary<TcpState, int>? tcpStats,
CancellationToken cancellationToken = default) where TResponse : TransportResponse, new()
{
var details = InitializeApiCallDetails(endpoint, boundConfiguration, postData, ex, statusCode, headers, contentType, threadPoolStats, tcpStats, contentLength);
TResponse? response = null;
if (responseStream is not null && MayHaveBody(statusCode, endpoint.Method, contentLength)
&& TryResolveBuilder<TResponse>(boundConfiguration.ResponseBuilders, boundConfiguration.ProductResponseBuilders, out var builder))
{
var ownsStream = false;
// We always pre-buffer when there may be a body, even if the content type does not match.
// That way, we ensure the caller can access the bytes themselves for "invalid" responses.
if (boundConfiguration.DisableDirectStreaming)
{
var inMemoryStream = boundConfiguration.MemoryStreamFactory.Create();
if (isAsync)
await responseStream.CopyToAsync(inMemoryStream, BufferedResponseHelpers.BufferSize, cancellationToken).ConfigureAwait(false);
else
responseStream.CopyTo(inMemoryStream, BufferedResponseHelpers.BufferSize);
details.ResponseBodyInBytes = BufferedResponseHelpers.SwapStreams(ref responseStream, ref inMemoryStream);
ownsStream = true;
}
// We only attempt to build a response when the Content-Type matches the accepted type.
if (ValidateResponseContentType(boundConfiguration.Accept, contentType))
{
if (isAsync)
response = await builder.BuildAsync<TResponse>(details, boundConfiguration, responseStream, contentType, contentLength, cancellationToken).ConfigureAwait(false);
else
response = builder.Build<TResponse>(details, boundConfiguration, responseStream, contentType, contentLength);
}
if (ownsStream && (response is null || !response.LeaveOpen))
responseStream?.Dispose();
}
response ??= new TResponse();
response.ApiCallDetails = details;
return response;
}