diff --git a/websocket-sharp/HttpBase.cs b/websocket-sharp/HttpBase.cs index 393a241a..4468a5bd 100644 --- a/websocket-sharp/HttpBase.cs +++ b/websocket-sharp/HttpBase.cs @@ -27,8 +27,11 @@ #endregion using System; +using System.Collections.Generic; using System.Collections.Specialized; +using System.IO; using System.Text; +using System.Threading; using WebSocketSharp.Net; namespace WebSocketSharp @@ -38,6 +41,7 @@ namespace WebSocketSharp #region Private Fields private NameValueCollection _headers; + private const int _headersMaxLength = 8192; private Version _version; #endregion @@ -48,7 +52,7 @@ namespace WebSocketSharp #endregion - #region Protected Const Fields + #region Protected Fields protected const string CrLf = "\r\n"; @@ -107,6 +111,96 @@ namespace WebSocketSharp return Encoding.GetEncoding (charset); } + private static byte[] readEntityBody (Stream stream, string length) + { + long len; + if (!Int64.TryParse (length, out len)) + throw new ArgumentException ("Cannot be parsed.", "length"); + + if (len < 0) + throw new ArgumentOutOfRangeException ("length", "Less than zero."); + + return len > 1024 + ? stream.ReadBytes (len, 1024) + : len > 0 + ? stream.ReadBytes ((int) len) + : null; + } + + private static string[] readHeaders (Stream stream, int maxLength) + { + var buff = new List (); + var cnt = 0; + Action add = i => { + buff.Add ((byte) i); + cnt++; + }; + + var read = false; + while (cnt < maxLength) { + if (stream.ReadByte ().EqualsWith ('\r', add) && + stream.ReadByte ().EqualsWith ('\n', add) && + stream.ReadByte ().EqualsWith ('\r', add) && + stream.ReadByte ().EqualsWith ('\n', add)) { + read = true; + break; + } + } + + if (!read) + throw new WebSocketException ("The length of header part is greater than the max length."); + + return Encoding.UTF8.GetString (buff.ToArray ()) + .Replace (CrLf + " ", " ") + .Replace (CrLf + "\t", " ") + .Split (new[] { CrLf }, StringSplitOptions.RemoveEmptyEntries); + } + + #endregion + + #region Protected Methods + + protected static T Read (Stream stream, Func parser, int millisecondsTimeout) + where T : HttpBase + { + var timeout = false; + var timer = new Timer ( + state => { + timeout = true; + stream.Close (); + }, + null, + millisecondsTimeout, + -1); + + T http = null; + Exception exception = null; + try { + http = parser (readHeaders (stream, _headersMaxLength)); + var contentLen = http.Headers["Content-Length"]; + if (contentLen != null && contentLen.Length > 0) + http.EntityBodyData = readEntityBody (stream, contentLen); + } + catch (Exception ex) { + exception = ex; + } + finally { + timer.Change (-1, -1); + timer.Dispose (); + } + + var msg = timeout + ? "A timeout has occurred while reading an HTTP request/response." + : exception != null + ? "An exception has occurred while reading an HTTP request/response." + : null; + + if (msg != null) + throw new WebSocketException (msg, exception); + + return http; + } + #endregion #region Public Methods diff --git a/websocket-sharp/HttpRequest.cs b/websocket-sharp/HttpRequest.cs index 4421d98f..9a69abcb 100644 --- a/websocket-sharp/HttpRequest.cs +++ b/websocket-sharp/HttpRequest.cs @@ -28,6 +28,7 @@ using System; using System.Collections.Specialized; +using System.IO; using System.Text; using WebSocketSharp.Net; @@ -137,6 +138,14 @@ namespace WebSocketSharp return req; } + internal HttpResponse GetResponse (Stream stream, int millisecondsTimeout) + { + var buff = ToByteArray (); + stream.Write (buff, 0, buff.Length); + + return Read (stream, HttpResponse.Parse, millisecondsTimeout); + } + internal static HttpRequest Parse (string[] headerParts) { var requestLine = headerParts[0].Split (new[] { ' ' }, 3); @@ -151,6 +160,11 @@ namespace WebSocketSharp requestLine[0], requestLine[1], new Version (requestLine[2].Substring (5)), headers); } + internal static HttpRequest Read (Stream stream, int millisecondsTimeout) + { + return Read (stream, Parse, millisecondsTimeout); + } + #endregion #region Public Methods diff --git a/websocket-sharp/HttpResponse.cs b/websocket-sharp/HttpResponse.cs index 7332b801..a8262f47 100644 --- a/websocket-sharp/HttpResponse.cs +++ b/websocket-sharp/HttpResponse.cs @@ -28,6 +28,7 @@ using System; using System.Collections.Specialized; +using System.IO; using System.Text; using WebSocketSharp.Net; @@ -173,6 +174,11 @@ namespace WebSocketSharp statusLine[1], statusLine[2], new Version (statusLine[0].Substring (5)), headers); } + internal static HttpResponse Read (Stream stream, int millisecondsTimeout) + { + return Read (stream, Parse, millisecondsTimeout); + } + #endregion #region Public Methods diff --git a/websocket-sharp/WebSocketStream.cs b/websocket-sharp/WebSocketStream.cs index 77f51982..21714972 100644 --- a/websocket-sharp/WebSocketStream.cs +++ b/websocket-sharp/WebSocketStream.cs @@ -27,12 +27,9 @@ #endregion using System; -using System.Collections.Generic; using System.IO; using System.Net.Sockets; using System.Security.Cryptography.X509Certificates; -using System.Text; -using System.Threading; using WebSocketSharp.Net; using WebSocketSharp.Net.Security; @@ -40,12 +37,6 @@ namespace WebSocketSharp { internal class WebSocketStream : IDisposable { - #region Private Const Fields - - private const int _headersMaxLength = 8192; - - #endregion - #region Private Fields private Stream _innerStream; @@ -81,106 +72,6 @@ namespace WebSocketSharp #endregion - #region Private Methods - - private static T read (Stream stream, Func parser, int millisecondsTimeout) - where T : HttpBase - { - var timeout = false; - var timer = new Timer ( - state => { - timeout = true; - stream.Close (); - }, - null, - millisecondsTimeout, - -1); - - T http = null; - Exception exception = null; - try { - http = parser (readHeaders (stream, _headersMaxLength)); - var contentLen = http.Headers["Content-Length"]; - if (contentLen != null && contentLen.Length > 0) - http.EntityBodyData = readEntityBody (stream, contentLen); - } - catch (Exception ex) { - exception = ex; - } - finally { - timer.Change (-1, -1); - timer.Dispose (); - } - - var msg = timeout - ? "A timeout has occurred while reading an HTTP request/response." - : exception != null - ? "An exception has occurred while reading an HTTP request/response." - : null; - - if (msg != null) - throw new WebSocketException (msg, exception); - - return http; - } - - private static byte[] readEntityBody (Stream stream, string length) - { - long len; - if (!Int64.TryParse (length, out len)) - throw new ArgumentException ("Cannot be parsed.", "length"); - - if (len < 0) - throw new ArgumentOutOfRangeException ("length", "Less than zero."); - - return len > 1024 - ? stream.ReadBytes (len, 1024) - : len > 0 - ? stream.ReadBytes ((int) len) - : null; - } - - private static string[] readHeaders (Stream stream, int maxLength) - { - var buff = new List (); - var cnt = 0; - Action add = i => { - buff.Add ((byte) i); - cnt++; - }; - - var read = false; - while (cnt < maxLength) { - if (stream.ReadByte ().EqualsWith ('\r', add) && - stream.ReadByte ().EqualsWith ('\n', add) && - stream.ReadByte ().EqualsWith ('\r', add) && - stream.ReadByte ().EqualsWith ('\n', add)) { - read = true; - break; - } - } - - if (!read) - throw new WebSocketException ("The length of header part is greater than the max length."); - - var crlf = "\r\n"; - return Encoding.UTF8.GetString (buff.ToArray ()) - .Replace (crlf + " ", " ") - .Replace (crlf + "\t", " ") - .Split (new[] { crlf }, StringSplitOptions.RemoveEmptyEntries); - } - - private static HttpResponse sendHttpRequest ( - Stream stream, HttpRequest request, int millisecondsTimeout) - { - var buff = request.ToByteArray (); - stream.Write (buff, 0, buff.Length); - - return read (stream, HttpResponse.Parse, millisecondsTimeout); - } - - #endregion - #region Internal Methods internal static WebSocketStream CreateClientStream ( @@ -199,7 +90,7 @@ namespace WebSocketSharp var netStream = tcpClient.GetStream (); if (proxy) { var req = HttpRequest.CreateConnectRequest (targetUri); - var res = sendHttpRequest (netStream, req, 90000); + var res = req.GetResponse (netStream, 90000); if (res.IsProxyAuthenticationRequired) { var authChal = res.ProxyAuthenticationChallenge; if (authChal != null && proxyCredentials != null) { @@ -213,7 +104,7 @@ namespace WebSocketSharp var authRes = new AuthenticationResponse (authChal, proxyCredentials, 0); req.Headers["Proxy-Authorization"] = authRes.ToString (); - res = sendHttpRequest (netStream, req, 15000); + res = req.GetResponse (netStream, 15000); } if (res.IsProxyAuthenticationRequired) @@ -256,12 +147,12 @@ namespace WebSocketSharp internal HttpRequest ReadHttpRequest (int millisecondsTimeout) { - return read (_innerStream, HttpRequest.Parse, millisecondsTimeout); + return HttpRequest.Read (_innerStream, millisecondsTimeout); } internal HttpResponse ReadHttpResponse (int millisecondsTimeout) { - return read (_innerStream, HttpResponse.Parse, millisecondsTimeout); + return HttpResponse.Read (_innerStream, millisecondsTimeout); } internal WebSocketFrame ReadWebSocketFrame () @@ -277,7 +168,7 @@ namespace WebSocketSharp internal HttpResponse SendHttpRequest (HttpRequest request, int millisecondsTimeout) { - return sendHttpRequest (_innerStream, request, millisecondsTimeout); + return request.GetResponse (_innerStream, millisecondsTimeout); } internal bool WriteBytes (byte[] data)