Skip to content

Commit 3d5fb24

Browse files
authored
Socket Exhaustion Fix (#32)
Creating a new HttpClient for every request can lead to socket exhaustion. This slight modification will mitigate this issue. More info can be found here: docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=netcore-1.0
1 parent 24af070 commit 3d5fb24

File tree

1 file changed

+25
-28
lines changed

1 file changed

+25
-28
lines changed

src/stream-net/Rest/RestClient.cs

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22
using System.Net;
33
using System.Net.Http;
44
using System.Text;
5+
using System.Threading;
56
using System.Threading.Tasks;
67

78
namespace Stream.Rest
89
{
910
internal class RestClient
1011
{
11-
readonly Uri _baseUrl;
12+
private static readonly HttpClient _client = new HttpClient();
13+
private readonly Uri _baseUrl;
1214
private TimeSpan _timeout;
1315

1416
public RestClient(Uri baseUrl, TimeSpan timeout)
@@ -17,25 +19,26 @@ public RestClient(Uri baseUrl, TimeSpan timeout)
1719
_timeout = timeout;
1820
}
1921

20-
private HttpClient BuildClient(RestRequest request)
22+
private HttpRequestMessage BuildRequestMessage(System.Net.Http.HttpMethod method, Uri url, RestRequest request)
2123
{
2224
#if NET45
2325
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
2426
#endif
25-
var client = new HttpClient();
26-
27-
client.DefaultRequestHeaders.Accept.Clear();
28-
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
29-
30-
client.Timeout = _timeout;
27+
var requestMessage = new HttpRequestMessage(method, url);
28+
requestMessage.Headers.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
3129

3230
// add request headers
3331
request.Headers.ForEach(h =>
3432
{
35-
client.DefaultRequestHeaders.Add(h.Key, h.Value);
33+
requestMessage.Headers.Add(h.Key, h.Value);
3634
});
3735

38-
return client;
36+
if (method == System.Net.Http.HttpMethod.Post || method == System.Net.Http.HttpMethod.Put)
37+
{
38+
requestMessage.Content = new StringContent(request.JsonBody, Encoding.UTF8, "application/json");
39+
}
40+
41+
return requestMessage;
3942
}
4043

4144
public TimeSpan Timeout
@@ -44,40 +47,34 @@ public TimeSpan Timeout
4447
set { _timeout = value; }
4548
}
4649

47-
private async Task<RestResponse> ExecuteGet(Uri url, RestRequest request)
50+
private async Task<RestResponse> ExecuteHttpRequest(System.Net.Http.HttpMethod method, Uri url, RestRequest request)
4851
{
49-
using (var client = BuildClient(request))
52+
var requestMessage = BuildRequestMessage(method, url, request);
53+
using (var cts = new CancellationTokenSource(_timeout))
5054
{
51-
HttpResponseMessage response = await client.GetAsync(url);
55+
HttpResponseMessage response = await _client.SendAsync(requestMessage, cts.Token);
5256
return await RestResponse.FromResponseMessage(response);
5357
}
5458
}
5559

60+
private async Task<RestResponse> ExecuteGet(Uri url, RestRequest request)
61+
{
62+
return await ExecuteHttpRequest(System.Net.Http.HttpMethod.Get, url, request);
63+
}
64+
5665
private async Task<RestResponse> ExecutePost(Uri url, RestRequest request)
5766
{
58-
using (var client = BuildClient(request))
59-
{
60-
HttpResponseMessage response = await client.PostAsync(url, new StringContent(request.JsonBody, Encoding.UTF8, "application/json"));
61-
return await RestResponse.FromResponseMessage(response);
62-
}
67+
return await ExecuteHttpRequest(System.Net.Http.HttpMethod.Post, url, request);
6368
}
6469

6570
private async Task<RestResponse> ExecutePut(Uri url, RestRequest request)
6671
{
67-
using (var client = BuildClient(request))
68-
{
69-
HttpResponseMessage response = await client.PutAsync(url, new StringContent(request.JsonBody, Encoding.UTF8, "application/json"));
70-
return await RestResponse.FromResponseMessage(response);
71-
}
72+
return await ExecuteHttpRequest(System.Net.Http.HttpMethod.Put, url, request);
7273
}
7374

7475
private async Task<RestResponse> ExecuteDelete(Uri url, RestRequest request)
7576
{
76-
using (var client = BuildClient(request))
77-
{
78-
HttpResponseMessage response = await client.DeleteAsync(url);
79-
return await RestResponse.FromResponseMessage(response);
80-
}
77+
return await ExecuteHttpRequest(System.Net.Http.HttpMethod.Delete, url, request);
8178
}
8279

8380
private Uri BuildUri(RestRequest request)

0 commit comments

Comments
 (0)