Skip to content

Commit 9a23dfa

Browse files
authored
Merge pull request #120 from cnblogs/hotfix/infinite-loop-in-TextSocketHelper
Fix infinite loop issue in TextSocketHelper.ReadLine
2 parents 32ab650 + f42d21a commit 9a23dfa

File tree

1 file changed

+121
-117
lines changed

1 file changed

+121
-117
lines changed

Enyim.Caching/Memcached/Protocol/Text/TextSocketHelper.cs

Lines changed: 121 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1,126 +1,130 @@
1-
using System;
1+
using System;
22
using System.IO;
33
using System.Text;
44
using System.Collections.Generic;
55

66
namespace Enyim.Caching.Memcached.Protocol.Text
77
{
8-
internal static class TextSocketHelper
9-
{
10-
private const string GenericErrorResponse = "ERROR";
11-
private const string ClientErrorResponse = "CLIENT_ERROR ";
12-
private const string ServerErrorResponse = "SERVER_ERROR ";
13-
private const int ErrorResponseLength = 13;
14-
15-
public const string CommandTerminator = "\r\n";
16-
17-
private static readonly Enyim.Caching.ILog log = Enyim.Caching.LogManager.GetLogger(typeof(TextSocketHelper));
18-
19-
/// <summary>
20-
/// Reads the response of the server.
21-
/// </summary>
22-
/// <returns>The data sent by the memcached server.</returns>
23-
/// <exception cref="T:System.InvalidOperationException">The server did not sent a response or an empty line was returned.</exception>
24-
/// <exception cref="T:Enyim.Caching.Memcached.MemcachedException">The server did not specified any reason just returned the string ERROR. - or - The server returned a SERVER_ERROR, in this case the Message of the exception is the message returned by the server.</exception>
25-
/// <exception cref="T:Enyim.Caching.Memcached.MemcachedClientException">The server did not recognize the request sent by the client. The Message of the exception is the message returned by the server.</exception>
26-
public static string ReadResponse(PooledSocket socket)
27-
{
28-
string response = TextSocketHelper.ReadLine(socket);
29-
30-
if (log.IsDebugEnabled)
31-
log.Debug("Received response: " + response);
32-
33-
if (String.IsNullOrEmpty(response))
34-
throw new MemcachedClientException("Empty response received.");
35-
36-
if (String.Compare(response, GenericErrorResponse, StringComparison.Ordinal) == 0)
37-
throw new NotSupportedException("Operation is not supported by the server or the request was malformed. If the latter please report the bug to the developers.");
38-
39-
if (response.Length >= ErrorResponseLength)
40-
{
41-
if (String.Compare(response, 0, ClientErrorResponse, 0, ErrorResponseLength, StringComparison.Ordinal) == 0)
42-
{
43-
throw new MemcachedClientException(response.Remove(0, ErrorResponseLength));
44-
}
45-
else if (String.Compare(response, 0, ServerErrorResponse, 0, ErrorResponseLength, StringComparison.Ordinal) == 0)
46-
{
47-
throw new MemcachedException(response.Remove(0, ErrorResponseLength));
48-
}
49-
}
50-
51-
return response;
52-
}
53-
54-
55-
/// <summary>
56-
/// Reads a line from the socket. A line is terninated by \r\n.
57-
/// </summary>
58-
/// <returns></returns>
59-
private static string ReadLine(PooledSocket socket)
60-
{
61-
MemoryStream ms = new MemoryStream(50);
62-
63-
bool gotR = false;
64-
//byte[] buffer = new byte[1];
65-
66-
int data;
67-
68-
while (true)
69-
{
70-
data = socket.ReadByte();
71-
72-
if (data == 13)
73-
{
74-
gotR = true;
75-
continue;
76-
}
77-
78-
if (gotR)
79-
{
80-
if (data == 10)
81-
break;
82-
83-
ms.WriteByte(13);
84-
85-
gotR = false;
86-
}
87-
88-
ms.WriteByte((byte)data);
89-
}
90-
91-
string retval = Encoding.ASCII.GetString(ms.ToArray(), 0, (int)ms.Length);
92-
93-
if (log.IsDebugEnabled)
94-
log.Debug("ReadLine: " + retval);
95-
96-
return retval;
97-
}
98-
99-
/// <summary>
100-
/// Gets the bytes representing the specified command. returned buffer can be used to streamline multiple writes into one Write on the Socket
101-
/// using the <see cref="M:Enyim.Caching.Memcached.PooledSocket.Write(IList&lt;ArraySegment&lt;byte&gt;&gt;)"/>
102-
/// </summary>
103-
/// <param name="value">The command to be converted.</param>
104-
/// <returns>The buffer containing the bytes representing the command. The command must be terminated by \r\n.</returns>
105-
/// <remarks>The Nagle algorithm is disabled on the socket to speed things up, so it's recommended to convert a command into a buffer
106-
/// and use the <see cref="M:Enyim.Caching.Memcached.PooledSocket.Write(IList&lt;ArraySegment&lt;byte&gt;&gt;)"/> to send the command and the additional buffers in one transaction.</remarks>
107-
public unsafe static IList<ArraySegment<byte>> GetCommandBuffer(string value)
108-
{
109-
var data = new ArraySegment<byte>(Encoding.ASCII.GetBytes(value));
110-
111-
return new ArraySegment<byte>[] { data };
112-
}
113-
114-
public unsafe static IList<ArraySegment<byte>> GetCommandBuffer(string value, IList<ArraySegment<byte>> list)
115-
{
116-
var data = new ArraySegment<byte>(Encoding.ASCII.GetBytes(value));
117-
118-
list.Add(data);
119-
120-
return list;
121-
}
122-
123-
}
8+
internal static class TextSocketHelper
9+
{
10+
private const string GenericErrorResponse = "ERROR";
11+
private const string ClientErrorResponse = "CLIENT_ERROR ";
12+
private const string ServerErrorResponse = "SERVER_ERROR ";
13+
private const int ErrorResponseLength = 13;
14+
15+
public const string CommandTerminator = "\r\n";
16+
17+
private static readonly Enyim.Caching.ILog log = Enyim.Caching.LogManager.GetLogger(typeof(TextSocketHelper));
18+
19+
/// <summary>
20+
/// Reads the response of the server.
21+
/// </summary>
22+
/// <returns>The data sent by the memcached server.</returns>
23+
/// <exception cref="T:System.InvalidOperationException">The server did not sent a response or an empty line was returned.</exception>
24+
/// <exception cref="T:Enyim.Caching.Memcached.MemcachedException">The server did not specified any reason just returned the string ERROR. - or - The server returned a SERVER_ERROR, in this case the Message of the exception is the message returned by the server.</exception>
25+
/// <exception cref="T:Enyim.Caching.Memcached.MemcachedClientException">The server did not recognize the request sent by the client. The Message of the exception is the message returned by the server.</exception>
26+
public static string ReadResponse(PooledSocket socket)
27+
{
28+
string response = TextSocketHelper.ReadLine(socket);
29+
30+
if (log.IsDebugEnabled)
31+
log.Debug("Received response: " + response);
32+
33+
if (String.IsNullOrEmpty(response))
34+
throw new MemcachedClientException("Empty response received.");
35+
36+
if (String.Compare(response, GenericErrorResponse, StringComparison.Ordinal) == 0)
37+
throw new NotSupportedException("Operation is not supported by the server or the request was malformed. If the latter please report the bug to the developers.");
38+
39+
if (response.Length >= ErrorResponseLength)
40+
{
41+
if (String.Compare(response, 0, ClientErrorResponse, 0, ErrorResponseLength, StringComparison.Ordinal) == 0)
42+
{
43+
throw new MemcachedClientException(response.Remove(0, ErrorResponseLength));
44+
}
45+
else if (String.Compare(response, 0, ServerErrorResponse, 0, ErrorResponseLength, StringComparison.Ordinal) == 0)
46+
{
47+
throw new MemcachedException(response.Remove(0, ErrorResponseLength));
48+
}
49+
}
50+
51+
return response;
52+
}
53+
54+
/// <summary>
55+
/// Reads a line from the socket. A line is terninated by \r\n.
56+
/// </summary>
57+
/// <returns></returns>
58+
private static string ReadLine(PooledSocket socket)
59+
{
60+
var ms = new MemoryStream(50);
61+
62+
bool gotR = false;
63+
//byte[] buffer = new byte[1];
64+
65+
int data;
66+
67+
while (true)
68+
{
69+
data = socket.ReadByte();
70+
71+
if (data == -1)
72+
{
73+
return string.Empty;
74+
}
75+
76+
if (data == 13)
77+
{
78+
gotR = true;
79+
continue;
80+
}
81+
82+
if (gotR)
83+
{
84+
if (data == 10)
85+
break;
86+
87+
ms.WriteByte(13);
88+
89+
gotR = false;
90+
}
91+
92+
ms.WriteByte((byte)data);
93+
}
94+
95+
string retval = Encoding.ASCII.GetString(ms.ToArray(), 0, (int)ms.Length);
96+
97+
if (log.IsDebugEnabled)
98+
log.Debug("ReadLine: " + retval);
99+
100+
return retval;
101+
}
102+
103+
/// <summary>
104+
/// Gets the bytes representing the specified command. returned buffer can be used to streamline multiple writes into one Write on the Socket
105+
/// using the <see cref="M:Enyim.Caching.Memcached.PooledSocket.Write(IList&lt;ArraySegment&lt;byte&gt;&gt;)"/>
106+
/// </summary>
107+
/// <param name="value">The command to be converted.</param>
108+
/// <returns>The buffer containing the bytes representing the command. The command must be terminated by \r\n.</returns>
109+
/// <remarks>The Nagle algorithm is disabled on the socket to speed things up, so it's recommended to convert a command into a buffer
110+
/// and use the <see cref="M:Enyim.Caching.Memcached.PooledSocket.Write(IList&lt;ArraySegment&lt;byte&gt;&gt;)"/> to send the command and the additional buffers in one transaction.</remarks>
111+
public unsafe static IList<ArraySegment<byte>> GetCommandBuffer(string value)
112+
{
113+
var data = new ArraySegment<byte>(Encoding.ASCII.GetBytes(value));
114+
115+
return new ArraySegment<byte>[] { data };
116+
}
117+
118+
public unsafe static IList<ArraySegment<byte>> GetCommandBuffer(string value, IList<ArraySegment<byte>> list)
119+
{
120+
var data = new ArraySegment<byte>(Encoding.ASCII.GetBytes(value));
121+
122+
list.Add(data);
123+
124+
return list;
125+
}
126+
127+
}
124128
}
125129

126130
#region [ License information ]

0 commit comments

Comments
 (0)