Skip to content

Commit 4743d7b

Browse files
authored
Ensure we dispose of the response stream in all cases (#5785) (#5787)
(cherry picked from commit 364ca23)
1 parent a3b7f2e commit 4743d7b

File tree

2 files changed

+20
-7
lines changed

2 files changed

+20
-7
lines changed

src/Elasticsearch.Net/Connection/HttpWebRequestConnection.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
namespace Elasticsearch.Net
2020
{
2121
#if DOTNETCORE
22-
[Obsolete("CoreFX HttpWebRequest uses HttpClient under the covers but does not reuse HttpClient instances, do NOT use on .NET core only used as the default on Full Framework")]
22+
[Obsolete(
23+
"CoreFX HttpWebRequest uses HttpClient under the covers but does not reuse HttpClient instances, do NOT use on .NET core only used as the default on Full Framework")]
2324
#endif
2425
public class HttpWebRequestConnection : IConnection
2526
{
@@ -52,8 +53,10 @@ public virtual TResponse Request<TResponse>(RequestData requestData)
5253
using (var stream = request.GetRequestStream())
5354
{
5455
if (requestData.HttpCompression)
56+
{
5557
using (var zipStream = new GZipStream(stream, CompressionMode.Compress))
5658
data.Write(zipStream, requestData.ConnectionSettings);
59+
}
5760
else
5861
data.Write(stream, requestData.ConnectionSettings);
5962
}
@@ -68,7 +71,7 @@ public virtual TResponse Request<TResponse>(RequestData requestData)
6871

6972
//http://msdn.microsoft.com/en-us/library/system.net.httpwebresponse.getresponsestream.aspx
7073
//Either the stream or the response object needs to be closed but not both although it won't
71-
//throw any errors if both are closed atleast one of them has to be Closed.
74+
//throw any errors if both are closed at least one of them has to be Closed.
7275
//Since we expose the stream we let closing the stream determining when to close the connection
7376
var httpWebResponse = (HttpWebResponse)request.GetResponse();
7477
HandleResponse(httpWebResponse, out statusCode, out responseStream, out mimeType);
@@ -125,8 +128,10 @@ CancellationToken cancellationToken
125128
using (var stream = await apmGetRequestStreamTask.ConfigureAwait(false))
126129
{
127130
if (requestData.HttpCompression)
131+
{
128132
using (var zipStream = new GZipStream(stream, CompressionMode.Compress))
129133
await data.WriteAsync(zipStream, requestData.ConnectionSettings, cancellationToken).ConfigureAwait(false);
134+
}
130135
else
131136
await data.WriteAsync(stream, requestData.ConnectionSettings, cancellationToken).ConfigureAwait(false);
132137
}
@@ -165,8 +170,7 @@ CancellationToken cancellationToken
165170
}
166171
responseStream ??= Stream.Null;
167172
var response = await ResponseBuilder.ToResponseAsync<TResponse>
168-
(requestData, ex, statusCode, warnings, responseStream, mimeType, cancellationToken)
169-
.ConfigureAwait(false);
173+
(requestData, ex, statusCode, warnings, responseStream, mimeType, cancellationToken).ConfigureAwait(false);
170174

171175
// set TCP and threadpool stats on the response here so that in the event the request fails after the point of
172176
// gathering stats, they are still exposed on the call details. Ideally these would be set inside ResponseBuilder.ToResponse,
@@ -205,7 +209,7 @@ protected virtual void SetServerCertificateValidationCallBackIfNeeded(HttpWebReq
205209
#else
206210
if (callback != null)
207211
throw new Exception("Mono misses ServerCertificateValidationCallback on HttpWebRequest");
208-
#endif
212+
#endif
209213
}
210214

211215
protected virtual HttpWebRequest CreateWebRequest(RequestData requestData)
@@ -311,8 +315,10 @@ protected virtual void SetBasicAuthenticationIfNeeded(HttpWebRequest request, Re
311315
if (!string.IsNullOrEmpty(requestData.Uri.UserInfo))
312316
userInfo = Uri.UnescapeDataString(requestData.Uri.UserInfo);
313317
else if (requestData.BasicAuthorizationCredentials != null)
318+
{
314319
userInfo =
315320
$"{requestData.BasicAuthorizationCredentials.Username}:{requestData.BasicAuthorizationCredentials.Password.CreateString()}";
321+
}
316322

317323
if (string.IsNullOrWhiteSpace(userInfo))
318324
return;
@@ -336,7 +342,6 @@ protected virtual bool SetApiKeyAuthenticationIfNeeded(HttpWebRequest request, R
336342

337343
request.Headers["Authorization"] = $"ApiKey {apiKey}";
338344
return true;
339-
340345
}
341346

342347
/// <summary>

src/Elasticsearch.Net/Transport/Pipeline/ResponseBuilder.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ public static TResponse ToResponse<TResponse>(
4141
// Only attempt to set the body if the response may have content
4242
if (MayHaveBody(statusCode, requestData.Method))
4343
response = SetBody<TResponse>(details, requestData, responseStream, mimeType);
44+
else
45+
responseStream.Dispose();
4446

4547
response ??= new TResponse();
4648

@@ -67,6 +69,8 @@ public static async Task<TResponse> ToResponseAsync<TResponse>(
6769
// Only attempt to set the body if the response may have content
6870
if (MayHaveBody(statusCode, requestData.Method))
6971
response = await SetBodyAsync<TResponse>(details, requestData, responseStream, mimeType, cancellationToken).ConfigureAwait(false);
72+
else
73+
responseStream.Dispose();
7074

7175
response ??= new TResponse();
7276

@@ -78,7 +82,7 @@ public static async Task<TResponse> ToResponseAsync<TResponse>(
7882
/// A helper which returns true if the response could potentially have a body.
7983
/// </summary>
8084
private static bool MayHaveBody(int? statusCode, HttpMethod httpMethod) =>
81-
!statusCode.HasValue || (statusCode.Value != 204 && httpMethod != HttpMethod.HEAD);
85+
!statusCode.HasValue || statusCode.Value != 204 && httpMethod != HttpMethod.HEAD;
8286

8387
private static ApiCallDetails Initialize(
8488
RequestData requestData, Exception exception, int? statusCode, IEnumerable<string> warnings, string mimeType
@@ -91,8 +95,10 @@ private static ApiCallDetails Initialize(
9195
if (allowedStatusCodes.Contains(-1) || allowedStatusCodes.Contains(statusCode.Value))
9296
success = true;
9397
else
98+
{
9499
success = requestData.ConnectionSettings
95100
.StatusCodeToResponseSuccess(requestData.Method, statusCode.Value);
101+
}
96102
}
97103

98104
// We don't validate the content-type (MIME type) for HEAD requests or responses that have no content (204 status code).
@@ -170,8 +176,10 @@ private static async Task<TResponse> SetBodyAsync<TResponse>(
170176

171177
var serializer = requestData.ConnectionSettings.RequestResponseSerializer;
172178
if (requestData.CustomResponseBuilder != null)
179+
{
173180
return await requestData.CustomResponseBuilder.DeserializeResponseAsync(serializer, details, responseStream, cancellationToken)
174181
.ConfigureAwait(false) as TResponse;
182+
}
175183

176184
return !RequestData.ValidResponseContentType(requestData.Accept, mimeType)
177185
? null

0 commit comments

Comments
 (0)