@@ -17,7 +17,9 @@ public static class ResponseBuilder
1717 public const int BufferSize = 81920 ;
1818
1919 private static readonly Type [ ] SpecialTypes =
20- { typeof ( StringResponse ) , typeof ( BytesResponse ) , typeof ( VoidResponse ) , typeof ( DynamicResponse ) } ;
20+ {
21+ typeof ( StringResponse ) , typeof ( BytesResponse ) , typeof ( VoidResponse ) , typeof ( DynamicResponse )
22+ } ;
2123
2224 public static TResponse ToResponse < TResponse > (
2325 RequestData requestData ,
@@ -31,8 +33,17 @@ public static TResponse ToResponse<TResponse>(
3133 {
3234 responseStream . ThrowIfNull ( nameof ( responseStream ) ) ;
3335 var details = Initialize ( requestData , ex , statusCode , warnings , mimeType ) ;
36+
3437 //TODO take ex and (responseStream == Stream.Null) into account might not need to flow to SetBody in that case
35- var response = SetBody < TResponse > ( details , requestData , responseStream , mimeType ) ?? new TResponse ( ) ;
38+
39+ TResponse response = null ;
40+
41+ // Only attempt to set the body if the response may have content
42+ if ( MayHaveBody ( statusCode , requestData . Method ) )
43+ response = SetBody < TResponse > ( details , requestData , responseStream , mimeType ) ;
44+
45+ response ??= new TResponse ( ) ;
46+
3647 response . ApiCall = details ;
3748 return response ;
3849 }
@@ -50,12 +61,25 @@ public static async Task<TResponse> ToResponseAsync<TResponse>(
5061 {
5162 responseStream . ThrowIfNull ( nameof ( responseStream ) ) ;
5263 var details = Initialize ( requestData , ex , statusCode , warnings , mimeType ) ;
53- var response = await SetBodyAsync < TResponse > ( details , requestData , responseStream , mimeType , cancellationToken ) . ConfigureAwait ( false )
54- ?? new TResponse ( ) ;
64+
65+ TResponse response = null ;
66+
67+ // Only attempt to set the body if the response may have content
68+ if ( MayHaveBody ( statusCode , requestData . Method ) )
69+ response = await SetBodyAsync < TResponse > ( details , requestData , responseStream , mimeType , cancellationToken ) . ConfigureAwait ( false ) ;
70+
71+ response ??= new TResponse ( ) ;
72+
5573 response . ApiCall = details ;
5674 return response ;
5775 }
5876
77+ /// <summary>
78+ /// A helper which returns true if the response could potentially have a body.
79+ /// </summary>
80+ private static bool MayHaveBody ( int ? statusCode , HttpMethod httpMethod ) =>
81+ ! statusCode . HasValue || ( statusCode . Value != 204 && httpMethod != HttpMethod . HEAD ) ;
82+
5983 private static ApiCallDetails Initialize (
6084 RequestData requestData , Exception exception , int ? statusCode , IEnumerable < string > warnings , string mimeType
6185 )
@@ -70,7 +94,10 @@ private static ApiCallDetails Initialize(
7094 success = requestData . ConnectionSettings
7195 . StatusCodeToResponseSuccess ( requestData . Method , statusCode . Value ) ;
7296 }
73- if ( ! RequestData . ValidResponseContentType ( requestData . Accept , mimeType ) )
97+
98+ // We don't validate the content-type (MIME type) for HEAD requests or responses that have no content (204 status code).
99+ // Elastic Cloud responses to HEAD requests strip the content-type header so we want to avoid validation in that case.
100+ if ( MayHaveBody ( statusCode , requestData . Method ) && ! RequestData . ValidResponseContentType ( requestData . Accept , mimeType ) )
74101 success = false ;
75102
76103 var details = new ApiCallDetails
@@ -143,7 +170,8 @@ private static async Task<TResponse> SetBodyAsync<TResponse>(
143170
144171 var serializer = requestData . ConnectionSettings . RequestResponseSerializer ;
145172 if ( requestData . CustomResponseBuilder != null )
146- return await requestData . CustomResponseBuilder . DeserializeResponseAsync ( serializer , details , responseStream , cancellationToken ) . ConfigureAwait ( false ) as TResponse ;
173+ return await requestData . CustomResponseBuilder . DeserializeResponseAsync ( serializer , details , responseStream , cancellationToken )
174+ . ConfigureAwait ( false ) as TResponse ;
147175
148176 return ! RequestData . ValidResponseContentType ( requestData . Accept , mimeType )
149177 ? null
@@ -171,8 +199,7 @@ private static bool SetSpecialTypes<TResponse>(string mimeType, byte[] bytes, IM
171199 //if not json store the result under "body"
172200 if ( ! RequestData . IsJsonMimeType ( mimeType ) )
173201 {
174- var dictionary = new DynamicDictionary ( ) ;
175- dictionary [ "body" ] = new DynamicValue ( bytes . Utf8String ( ) ) ;
202+ var dictionary = new DynamicDictionary { [ "body" ] = new ( bytes . Utf8String ( ) ) } ;
176203 cs = new DynamicResponse ( dictionary ) as TResponse ;
177204 }
178205 else
0 commit comments