Skip to content

Commit 592aadc

Browse files
authored
Exception handling & memory leak fixes (#150)
1 parent adbc836 commit 592aadc

2 files changed

Lines changed: 54 additions & 26 deletions

File tree

nanoFramework.System.Net.Http/Http/System.Net.HttpWebRequest.cs

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -73,36 +73,40 @@ public class HttpWebRequest : WebRequest
7373
/// <param name="unused">Unused</param>
7474
static private void CheckPersistentConnections(object unused)
7575
{
76+
// Persistent connections have not been properly implemented yet.
7677
int count = m_ConnectedStreams.Count;
78+
7779
// The fastest way to exit out - if there are no sockets in the list - exit out.
7880
if (count > 0)
7981
{
8082
DateTime curTime = DateTime.UtcNow;
83+
8184
lock (m_ConnectedStreams)
8285
{
8386
count = m_ConnectedStreams.Count;
8487

85-
for (int i = count-1; i >= 0; i--)
88+
for (int i = count - 1; i >= 0; i--)
8689
{
8790
InputNetworkStreamWrapper streamWrapper = (InputNetworkStreamWrapper)m_ConnectedStreams[i];
8891

89-
TimeSpan timePassed = streamWrapper.m_lastUsed - curTime;
92+
TimeSpan timePassed = curTime - streamWrapper.m_lastUsed;
9093

9194
// If the socket is old, then close and remove from the list.
92-
if (timePassed.Milliseconds > HttpConstants.DefaultKeepAliveMilliseconds)
95+
if (timePassed.TotalMilliseconds > HttpConstants.DefaultKeepAliveMilliseconds)
9396
{
9497
m_ConnectedStreams.RemoveAt(i);
95-
98+
9699
// Closes the socket to release resources.
97100
streamWrapper.Dispose();
98101
}
99102
}
100103

101104
// turn off the timer if there are no active streams
102-
if(m_ConnectedStreams.Count > 0)
105+
if (m_ConnectedStreams.Count > 0)
103106
{
104-
m_DropOldConnectionsTimer.Change( HttpConstants.DefaultKeepAliveMilliseconds, System.Threading.Timeout.Infinite );
107+
m_DropOldConnectionsTimer.Change(HttpConstants.DefaultKeepAliveMilliseconds, System.Threading.Timeout.Infinite);
105108
}
109+
106110
}
107111
}
108112
}
@@ -1336,8 +1340,8 @@ private InputNetworkStreamWrapper EstablishConnection(Uri proxyServer, Uri targe
13361340
// But first we need to know that socket is not closed.
13371341
try
13381342
{
1339-
// If socket is closed ( from this or other side ) the call throws exception.
1340-
if (inputStream.m_Socket.Poll(1, SelectMode.SelectWrite))
1343+
// If socket is closed (from this or other side) the call throws exception.
1344+
if (inputStream.m_Socket.Poll(-1, SelectMode.SelectWrite))
13411345
{
13421346
// No exception, good we can condtinue and re-use connected stream.
13431347

@@ -1352,7 +1356,6 @@ private InputNetworkStreamWrapper EstablishConnection(Uri proxyServer, Uri targe
13521356
{
13531357
removeStreamList.Add(inputStream);
13541358
}
1355-
13561359
}
13571360
catch (Exception)
13581361
{
@@ -1415,13 +1418,15 @@ private InputNetworkStreamWrapper EstablishConnection(Uri proxyServer, Uri targe
14151418
}
14161419

14171420
// If socket was not found in waiting connections, then we create new one.
1418-
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
1421+
Socket socket = null;
1422+
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
14191423

14201424
try
14211425
{
14221426
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
14231427
}
14241428
catch{}
1429+
14251430
try
14261431
{
14271432
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
@@ -1436,6 +1441,9 @@ private InputNetworkStreamWrapper EstablishConnection(Uri proxyServer, Uri targe
14361441
}
14371442
catch (SocketException e)
14381443
{
1444+
// need to close socket, otherwise this will cause an out of memory exception
1445+
socket.Close();
1446+
14391447
throw new WebException("connection failed", e, WebExceptionStatus.ConnectFailure, null);
14401448
}
14411449

@@ -1476,14 +1484,18 @@ private InputNetworkStreamWrapper EstablishConnection(Uri proxyServer, Uri targe
14761484
retStream.m_rmAddrAndPort = m_originalUrl.Host + ":" + m_originalUrl.Port;
14771485
}
14781486

1479-
lock (m_ConnectedStreams)
1487+
// Check keepAlive before creating persistent connection - persistent connections are not currently supported
1488+
if (m_keepAlive)
14801489
{
1481-
m_ConnectedStreams.Add(retStream);
1482-
1483-
// if the current stream list is empty then start the timer that drops unused connections.
1484-
if (m_ConnectedStreams.Count == 1)
1490+
lock (m_ConnectedStreams)
14851491
{
1486-
m_DropOldConnectionsTimer.Change(HttpConstants.DefaultKeepAliveMilliseconds, System.Threading.Timeout.Infinite);
1492+
m_ConnectedStreams.Add(retStream);
1493+
1494+
// if the current stream list is empty then start the timer that drops unused connections.
1495+
if (m_ConnectedStreams.Count == 1)
1496+
{
1497+
m_DropOldConnectionsTimer.Change(HttpConstants.DefaultKeepAliveMilliseconds, System.Threading.Timeout.Infinite);
1498+
}
14871499
}
14881500
}
14891501
}
@@ -1499,14 +1511,16 @@ private void SubmitRequest()
14991511
// We have connected socket. Create request stream
15001512
// If proxy is set - connect to proxy server.
15011513

1502-
if(m_requestStream == null)
1514+
if (m_requestStream == null)
15031515
{
15041516
if (m_proxy == null)
1505-
{ // Direct connection to target server.
1517+
{
1518+
// Direct connection to target server.
15061519
m_requestStream = EstablishConnection(m_originalUrl, m_originalUrl);
15071520
}
1508-
else // Connection through proxy. We create network stream connected to proxy
1521+
else
15091522
{
1523+
// Connection through proxy. We create network stream connected to proxy
15101524
Uri proxyUri = m_proxy.GetProxy(m_originalUrl);
15111525

15121526
if (m_originalUrl.Scheme == "https")
@@ -1522,6 +1536,13 @@ private void SubmitRequest()
15221536
}
15231537
}
15241538

1539+
if (m_requestStream == null)
1540+
{
1541+
// Connection could not be established
1542+
m_requestSent = false;
1543+
return;
1544+
}
1545+
15251546
// We have connected stream. Set the timeout from HttpWebRequest
15261547
m_requestStream.WriteTimeout = m_readWriteTimeout;
15271548
m_requestStream.ReadTimeout = m_readWriteTimeout;
@@ -1725,6 +1746,12 @@ public override WebResponse GetResponse()
17251746
SubmitRequest();
17261747
}
17271748

1749+
// Need to check m_requestSent after SubmitRequest()
1750+
if (!m_requestSent)
1751+
{
1752+
return response;
1753+
}
1754+
17281755
CoreResponseData respData = null;
17291756

17301757
// reset the total response bytes for the new request.
@@ -1765,8 +1792,9 @@ public override WebResponse GetResponse()
17651792
m_responseStatus = response.StatusCode;
17661793

17671794
m_responseCreated = true;
1795+
m_requestStream.m_InUse = false; // Persistent connections are not yet supported, but they wouldn't work without this.
17681796
}
1769-
catch(SocketException se)
1797+
catch (SocketException se)
17701798
{
17711799
if (m_requestStream != null)
17721800
{
@@ -1777,12 +1805,11 @@ public override WebResponse GetResponse()
17771805
this.m_requestStream.m_Socket.Close();
17781806
}
17791807
}
1780-
1781-
throw new WebException("", se);
1808+
throw new WebException("GetResponse() failed", se);
17821809
}
1783-
catch(Exception e)
1810+
catch (Exception e)
17841811
{
1785-
throw new WebException("", e);
1812+
throw new WebException("GetResponse() failed", e);
17861813
}
17871814

17881815

nanoFramework.System.Net.Http/Http/System.Net._OutputNetworkStreamWrapper.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,9 @@ public override void Flush()
144144
// Calls HttpListenerResponse.SendHeaders. HttpListenerResponse.SendHeaders sets m_headersSend to null.
145145
m_headersSend();
146146
}
147-
148-
m_Stream.Flush();
147+
148+
// Need to check for null before using here
149+
m_Stream?.Flush();
149150
}
150151

151152
/// <summary>

0 commit comments

Comments
 (0)