diff --git a/websocket-sharp/Net/HttpConnection.cs b/websocket-sharp/Net/HttpConnection.cs index cd4b1f03..6c50a950 100644 --- a/websocket-sharp/Net/HttpConnection.cs +++ b/websocket-sharp/Net/HttpConnection.cs @@ -40,24 +40,19 @@ using System; using System.IO; using System.Net; +using System.Net.Security; using System.Net.Sockets; using System.Text; using System.Threading; -using WebSocketSharp.Net.Security; namespace WebSocketSharp.Net { internal sealed class HttpConnection { - #region Private Const Fields - - private const int _bufferSize = 8192; - - #endregion - #region Private Fields - private byte [] _buffer; + private byte[] _buffer; + private const int _bufferSize = 8192; private bool _chunked; private HttpListenerContext _context; private bool _contextWasBound; @@ -78,7 +73,6 @@ namespace WebSocketSharp.Net private object _sync; private int _timeout; private Timer _timer; - private WebSocketStream _websocketStream; #endregion @@ -205,7 +199,6 @@ namespace WebSocketSharp.Net _inputStream = null; _outputStream = null; - _websocketStream = null; _stream.Dispose (); _stream = null; @@ -317,7 +310,7 @@ namespace WebSocketSharp.Net // true -> Done processing. // false -> Need more input. - private bool processInput (byte [] data) + private bool processInput (byte[] data) { var len = data.Length; var used = 0; @@ -359,7 +352,7 @@ namespace WebSocketSharp.Net return false; } - private string readLine (byte [] buffer, int offset, int length, ref int used) + private string readLine (byte[] buffer, int offset, int length, ref int used) { if (_currentLine == null) _currentLine = new StringBuilder (); @@ -368,7 +361,7 @@ namespace WebSocketSharp.Net used = 0; for (int i = offset; i < last && _lineState != LineState.LF; i++) { used++; - var b = buffer [i]; + var b = buffer[i]; if (b == 13) _lineState = LineState.CR; else if (b == 10) @@ -447,7 +440,7 @@ namespace WebSocketSharp.Net public void BeginReadRequest () { if (_buffer == null) - _buffer = new byte [_bufferSize]; + _buffer = new byte[_bufferSize]; if (_reuses == 1) _timeout = 15000; @@ -512,20 +505,6 @@ namespace WebSocketSharp.Net } } - public WebSocketStream GetWebSocketStream () - { - if (_websocketStream != null || _socket == null) - return _websocketStream; - - lock (_sync) { - if (_socket == null) - return _websocketStream; - - _websocketStream = new WebSocketStream (_stream, _secure); - return _websocketStream; - } - } - public void SendError () { SendError (_context.ErrorMessage, _context.ErrorStatus); diff --git a/websocket-sharp/Net/Security/SslStream.cs b/websocket-sharp/Net/Security/SslStream.cs deleted file mode 100644 index 7588eeed..00000000 --- a/websocket-sharp/Net/Security/SslStream.cs +++ /dev/null @@ -1,82 +0,0 @@ -#region License -/* - * SslStream.cs - * - * The MIT License - * - * Copyright (c) 2012-2014 sta.blockhead - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#endregion - -using System; -using System.Net.Security; -using System.Net.Sockets; - -namespace WebSocketSharp.Net.Security -{ - internal class SslStream : System.Net.Security.SslStream - { - #region Public Constructors - - public SslStream (NetworkStream innerStream) - : base (innerStream) - { - } - - public SslStream (NetworkStream innerStream, bool leaveInnerStreamOpen) - : base (innerStream, leaveInnerStreamOpen) - { - } - - public SslStream ( - NetworkStream innerStream, - bool leaveInnerStreamOpen, - RemoteCertificateValidationCallback userCertificateValidationCallback) - : base (innerStream, leaveInnerStreamOpen, userCertificateValidationCallback) - { - } - - public SslStream ( - NetworkStream innerStream, - bool leaveInnerStreamOpen, - RemoteCertificateValidationCallback userCertificateValidationCallback, - LocalCertificateSelectionCallback userCertificateSelectionCallback) - : base ( - innerStream, - leaveInnerStreamOpen, - userCertificateValidationCallback, - userCertificateSelectionCallback) - { - } - - #endregion - - #region Public Properties - - public bool DataAvailable { - get { - return ((NetworkStream) InnerStream).DataAvailable; - } - } - - #endregion - } -} diff --git a/websocket-sharp/Net/WebSockets/HttpListenerWebSocketContext.cs b/websocket-sharp/Net/WebSockets/HttpListenerWebSocketContext.cs index 83c32e2f..23bff44a 100644 --- a/websocket-sharp/Net/WebSockets/HttpListenerWebSocketContext.cs +++ b/websocket-sharp/Net/WebSockets/HttpListenerWebSocketContext.cs @@ -29,6 +29,7 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; +using System.IO; using System.Security.Principal; namespace WebSocketSharp.Net.WebSockets @@ -37,8 +38,6 @@ namespace WebSocketSharp.Net.WebSockets /// Provides the properties used to access the information in a WebSocket connection request /// received by the . /// - /// - /// public class HttpListenerWebSocketContext : WebSocketContext { #region Private Fields @@ -61,9 +60,9 @@ namespace WebSocketSharp.Net.WebSockets #region Internal Properties - internal WebSocketStream Stream { + internal Stream Stream { get { - return _context.Connection.GetWebSocketStream (); + return _context.Connection.Stream; } } @@ -103,7 +102,7 @@ namespace WebSocketSharp.Net.WebSockets /// public override string Host { get { - return _context.Request.Headers ["Host"]; + return _context.Request.Headers["Host"]; } } @@ -163,7 +162,7 @@ namespace WebSocketSharp.Net.WebSockets /// public override string Origin { get { - return _context.Request.Headers ["Origin"]; + return _context.Request.Headers["Origin"]; } } @@ -203,7 +202,7 @@ namespace WebSocketSharp.Net.WebSockets /// public override string SecWebSocketKey { get { - return _context.Request.Headers ["Sec-WebSocket-Key"]; + return _context.Request.Headers["Sec-WebSocket-Key"]; } } @@ -220,7 +219,7 @@ namespace WebSocketSharp.Net.WebSockets /// public override IEnumerable SecWebSocketProtocols { get { - var protocols = _context.Request.Headers ["Sec-WebSocket-Protocol"]; + var protocols = _context.Request.Headers["Sec-WebSocket-Protocol"]; if (protocols != null) foreach (var protocol in protocols.Split (',')) yield return protocol.Trim (); @@ -238,7 +237,7 @@ namespace WebSocketSharp.Net.WebSockets /// public override string SecWebSocketVersion { get { - return _context.Request.Headers ["Sec-WebSocket-Version"]; + return _context.Request.Headers["Sec-WebSocket-Version"]; } } diff --git a/websocket-sharp/Net/WebSockets/TcpListenerWebSocketContext.cs b/websocket-sharp/Net/WebSockets/TcpListenerWebSocketContext.cs index dbd30b13..1e6aa9ab 100644 --- a/websocket-sharp/Net/WebSockets/TcpListenerWebSocketContext.cs +++ b/websocket-sharp/Net/WebSockets/TcpListenerWebSocketContext.cs @@ -29,6 +29,8 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; +using System.IO; +using System.Net.Security; using System.Net.Sockets; using System.Security.Cryptography.X509Certificates; using System.Security.Principal; @@ -48,7 +50,7 @@ namespace WebSocketSharp.Net.WebSockets private NameValueCollection _queryString; private HttpRequest _request; private bool _secure; - private WebSocketStream _stream; + private Stream _stream; private TcpClient _tcpClient; private Uri _uri; private IPrincipal _user; @@ -63,8 +65,18 @@ namespace WebSocketSharp.Net.WebSockets { _tcpClient = tcpClient; _secure = secure; - _stream = WebSocketStream.CreateServerStream (tcpClient, secure, certificate); - _request = _stream.ReadHttpRequest (90000); + + var netStream = tcpClient.GetStream (); + if (secure) { + var sslStream = new SslStream (netStream, false); + sslStream.AuthenticateAsServer (certificate); + _stream = sslStream; + } + else { + _stream = netStream; + } + + _request = HttpRequest.Read (_stream, 90000); _uri = HttpUtility.CreateRequestUrl ( _request.RequestUri, _request.Headers["Host"], _request.IsWebSocketRequest, secure); @@ -75,7 +87,7 @@ namespace WebSocketSharp.Net.WebSockets #region Internal Properties - internal WebSocketStream Stream { + internal Stream Stream { get { return _stream; } @@ -324,8 +336,9 @@ namespace WebSocketSharp.Net.WebSockets internal void SendAuthenticationChallenge (string challenge) { - _stream.WriteBytes (HttpResponse.CreateUnauthorizedResponse (challenge).ToByteArray ()); - _request = _stream.ReadHttpRequest (15000); + var buff = HttpResponse.CreateUnauthorizedResponse (challenge).ToByteArray (); + _stream.Write (buff, 0, buff.Length); + _request = HttpRequest.Read (_stream, 15000); } internal void SetUser ( diff --git a/websocket-sharp/WebSocket.cs b/websocket-sharp/WebSocket.cs index 580eac2f..8420f88f 100644 --- a/websocket-sharp/WebSocket.cs +++ b/websocket-sharp/WebSocket.cs @@ -38,8 +38,8 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; using System.IO; -using System.Net.Sockets; using System.Net.Security; +using System.Net.Sockets; using System.Security.Cryptography; using System.Text; using System.Threading; @@ -90,7 +90,7 @@ namespace WebSocketSharp private volatile WebSocketState _readyState; private AutoResetEvent _receivePong; private bool _secure; - private WebSocketStream _stream; + private Stream _stream; private TcpClient _tcpClient; private Uri _uri; private const string _version = "13"; @@ -511,7 +511,7 @@ namespace WebSocketSharp if (extensions != null && extensions.Length > 0) processSecWebSocketExtensionsHeader (extensions); - return sendHandshakeResponse (createHandshakeResponse ()); + return sendHttpResponse (createHandshakeResponse ()); } private string checkIfAvailable ( @@ -629,7 +629,7 @@ namespace WebSocketSharp private bool closeHandshake (byte[] frameAsBytes, int millisecondsTimeout, Action release) { - var sent = frameAsBytes != null && _stream.WriteBytes (frameAsBytes); + var sent = frameAsBytes != null && writeBytes (frameAsBytes); var received = millisecondsTimeout == 0 || (sent && _exitReceiving != null && _exitReceiving.WaitOne (millisecondsTimeout)); @@ -667,7 +667,7 @@ namespace WebSocketSharp private bool concatenateFragmentsInto (Stream dest) { while (true) { - var frame = _stream.ReadWebSocketFrame (); + var frame = WebSocketFrame.Read (_stream, true); if (frame.IsFinal) { /* FINAL */ @@ -1045,7 +1045,7 @@ namespace WebSocketSharp return false; } - return _stream.WriteBytes (frameAsBytes); + return writeBytes (frameAsBytes); } } @@ -1135,7 +1135,7 @@ namespace WebSocketSharp return false; } - return _stream.WriteBytes ( + return writeBytes ( WebSocketFrame.CreateWebSocketFrame (fin, opcode, mask, data, compressed).ToByteArray ()); } } @@ -1164,7 +1164,7 @@ namespace WebSocketSharp private HttpResponse sendHandshakeRequest () { var req = createHandshakeRequest (); - var res = sendHandshakeRequest (req, 90000); + var res = sendHttpRequest (req, 90000); if (res.IsUnauthorized) { _authChallenge = res.AuthenticationChallenge; if (_credentials != null && @@ -1177,7 +1177,7 @@ namespace WebSocketSharp var authRes = new AuthenticationResponse (_authChallenge, _credentials, _nonceCount); _nonceCount = authRes.NonceCount; req.Headers["Authorization"] = authRes.ToString (); - res = sendHandshakeRequest (req, 15000); + res = sendHttpRequest (req, 15000); } } @@ -1185,31 +1185,74 @@ namespace WebSocketSharp } // As client - private HttpResponse sendHandshakeRequest (HttpRequest request, int millisecondsTimeout) + private HttpResponse sendHttpRequest (HttpRequest request, int millisecondsTimeout) { - _logger.Debug ( - String.Format ("A WebSocket connection request to {0}:\n{1}", _uri, request)); - - var res = _stream.SendHttpRequest (request, millisecondsTimeout); - _logger.Debug ("A response to this WebSocket connection request:\n" + res.ToString ()); + _logger.Debug ("A request to the server:\n" + request.ToString ()); + var res = request.GetResponse (_stream, millisecondsTimeout); + _logger.Debug ("A response to this request:\n" + res.ToString ()); return res; } // As server - private bool sendHandshakeResponse (HttpResponse response) + private bool sendHttpResponse (HttpResponse response) { - _logger.Debug ( - "A response to the WebSocket connection request:\n" + response.ToString ()); + _logger.Debug ("A response to this request:\n" + response.ToString ()); + return writeBytes (response.ToByteArray ()); + } - return _stream.WriteBytes (response.ToByteArray ()); + // As client + private HttpResponse sendProxyConnectRequest () + { + var req = HttpRequest.CreateConnectRequest (_uri); + var res = sendHttpRequest (req, 90000); + if (res.IsProxyAuthenticationRequired) { + var authChal = res.ProxyAuthenticationChallenge; + if (authChal != null && _proxyCredentials != null) { + if (res.Headers.Contains ("Connection", "close")) { + closeClientResources (); + _tcpClient = new TcpClient (_proxyUri.DnsSafeHost, _proxyUri.Port); + _stream = _tcpClient.GetStream (); + } + + var authRes = new AuthenticationResponse (authChal, _proxyCredentials, 0); + req.Headers["Proxy-Authorization"] = authRes.ToString (); + res = sendHttpRequest (req, 15000); + } + } + + return res; } // As client private void setClientStream () { - _stream = WebSocketStream.CreateClientStream ( - _uri, _proxyUri, _proxyCredentials, _secure, _certValidationCallback, out _tcpClient); + var proxy = _proxyUri != null; + _tcpClient = proxy + ? new TcpClient (_proxyUri.DnsSafeHost, _proxyUri.Port) + : new TcpClient (_uri.DnsSafeHost, _uri.Port); + + _stream = _tcpClient.GetStream (); + + if (proxy) { + var res = sendProxyConnectRequest (); + if (res.IsProxyAuthenticationRequired) + throw new WebSocketException ("Proxy authentication is required."); + + if (res.StatusCode[0] != '2') + throw new WebSocketException ( + "The proxy has failed a connection to the requested host and port."); + } + + if (_secure) { + var sslStream = new SslStream ( + _stream, + false, + _certValidationCallback ?? ((sender, certificate, chain, sslPolicyErrors) => true)); + + sslStream.AuthenticateAsClient (_uri.DnsSafeHost); + _stream = sslStream; + } } private void startReceiving () @@ -1221,7 +1264,9 @@ namespace WebSocketSharp _receivePong = new AutoResetEvent (false); Action receive = null; - receive = () => _stream.ReadWebSocketFrameAsync ( + receive = () => WebSocketFrame.ReadAsync ( + _stream, + true, frame => { if (processWebSocketFrame (frame) && _readyState != WebSocketState.Closed) { receive (); @@ -1313,6 +1358,18 @@ namespace WebSocketSharp return value == null || value == _version; } + private bool writeBytes (byte[] data) + { + try { + _stream.Write (data, 0, data.Length); + return true; + } + catch (Exception ex) { + _logger.Fatal (ex.ToString ()); + return false; + } + } + #endregion #region Internal Methods @@ -1322,7 +1379,7 @@ namespace WebSocketSharp { _readyState = WebSocketState.Closing; - sendHandshakeResponse (response); + sendHttpResponse (response); closeServerResources (); _readyState = WebSocketState.Closed; @@ -1430,11 +1487,10 @@ namespace WebSocketSharp cache.Add (_compression, cached); } - if (!_stream.WriteBytes (cached)) - _logger.Error ("Sending a data has been interrupted."); + writeBytes (cached); } catch (Exception ex) { - _logger.Fatal ("An exception has occurred while sending a data:\n" + ex.ToString ()); + _logger.Fatal (ex.ToString ()); } } } @@ -1454,12 +1510,10 @@ namespace WebSocketSharp cached.Position = 0; } - if (_readyState != WebSocketState.Open || - !send (opcode, Mask.Unmask, cached, _compression != CompressionMethod.None)) - _logger.Error ("Sending a data has been interrupted."); + send (opcode, Mask.Unmask, cached, _compression != CompressionMethod.None); } catch (Exception ex) { - _logger.Fatal ("An exception has occurred while sending a data:\n" + ex.ToString ()); + _logger.Fatal (ex.ToString ()); } } } diff --git a/websocket-sharp/WebSocketStream.cs b/websocket-sharp/WebSocketStream.cs deleted file mode 100644 index a451fd35..00000000 --- a/websocket-sharp/WebSocketStream.cs +++ /dev/null @@ -1,201 +0,0 @@ -#region License -/* - * WebSocketStream.cs - * - * The MIT License - * - * Copyright (c) 2010-2014 sta.blockhead - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#endregion - -using System; -using System.IO; -using System.Net.Sockets; -using System.Security.Cryptography.X509Certificates; -using WebSocketSharp.Net; -using WebSocketSharp.Net.Security; - -namespace WebSocketSharp -{ - internal class WebSocketStream : IDisposable - { - #region Private Fields - - private Stream _innerStream; - private bool _secure; - - #endregion - - #region Internal Constructors - - internal WebSocketStream (Stream innerStream, bool secure) - { - _innerStream = innerStream; - _secure = secure; - } - - #endregion - - #region Public Properties - - public bool DataAvailable { - get { - return _secure - ? ((SslStream) _innerStream).DataAvailable - : ((NetworkStream) _innerStream).DataAvailable; - } - } - - public bool IsSecure { - get { - return _secure; - } - } - - #endregion - - #region Internal Methods - - internal static WebSocketStream CreateClientStream ( - Uri targetUri, - Uri proxyUri, - NetworkCredential proxyCredentials, - bool secure, - System.Net.Security.RemoteCertificateValidationCallback validationCallback, - out TcpClient tcpClient) - { - var proxy = proxyUri != null; - tcpClient = proxy - ? new TcpClient (proxyUri.DnsSafeHost, proxyUri.Port) - : new TcpClient (targetUri.DnsSafeHost, targetUri.Port); - - var netStream = tcpClient.GetStream (); - if (proxy) { - var req = HttpRequest.CreateConnectRequest (targetUri); - var res = req.GetResponse (netStream, 90000); - if (res.IsProxyAuthenticationRequired) { - var authChal = res.ProxyAuthenticationChallenge; - if (authChal != null && proxyCredentials != null) { - if (res.Headers.Contains ("Connection", "close")) { - netStream.Dispose (); - tcpClient.Close (); - - tcpClient = new TcpClient (proxyUri.DnsSafeHost, proxyUri.Port); - netStream = tcpClient.GetStream (); - } - - var authRes = new AuthenticationResponse (authChal, proxyCredentials, 0); - req.Headers["Proxy-Authorization"] = authRes.ToString (); - res = req.GetResponse (netStream, 15000); - } - - if (res.IsProxyAuthenticationRequired) - throw new WebSocketException ("Proxy authentication is required."); - } - - var code = res.StatusCode; - if (code[0] != '2') - throw new WebSocketException ( - String.Format ( - "The proxy has failed a connection to the requested host and port. ({0})", code)); - } - - if (secure) { - var sslStream = new SslStream ( - netStream, - false, - validationCallback ?? ((sender, certificate, chain, sslPolicyErrors) => true)); - - sslStream.AuthenticateAsClient (targetUri.DnsSafeHost); - return new WebSocketStream (sslStream, secure); - } - - return new WebSocketStream (netStream, secure); - } - - internal static WebSocketStream CreateServerStream ( - TcpClient tcpClient, bool secure, X509Certificate certificate) - { - var netStream = tcpClient.GetStream (); - if (secure) { - var sslStream = new SslStream (netStream, false); - sslStream.AuthenticateAsServer (certificate); - - return new WebSocketStream (sslStream, secure); - } - - return new WebSocketStream (netStream, secure); - } - - internal HttpRequest ReadHttpRequest (int millisecondsTimeout) - { - return HttpRequest.Read (_innerStream, millisecondsTimeout); - } - - internal HttpResponse ReadHttpResponse (int millisecondsTimeout) - { - return HttpResponse.Read (_innerStream, millisecondsTimeout); - } - - internal WebSocketFrame ReadWebSocketFrame () - { - return WebSocketFrame.Read (_innerStream, true); - } - - internal void ReadWebSocketFrameAsync ( - Action completed, Action error) - { - WebSocketFrame.ReadAsync (_innerStream, true, completed, error); - } - - internal HttpResponse SendHttpRequest (HttpRequest request, int millisecondsTimeout) - { - return request.GetResponse (_innerStream, millisecondsTimeout); - } - - internal bool WriteBytes (byte[] data) - { - try { - _innerStream.Write (data, 0, data.Length); - return true; - } - catch { - return false; - } - } - - #endregion - - #region Public Methods - - public void Close () - { - _innerStream.Close (); - } - - public void Dispose () - { - _innerStream.Dispose (); - } - - #endregion - } -} diff --git a/websocket-sharp/websocket-sharp.csproj b/websocket-sharp/websocket-sharp.csproj index a4fe3079..a8f96d2c 100644 --- a/websocket-sharp/websocket-sharp.csproj +++ b/websocket-sharp/websocket-sharp.csproj @@ -94,7 +94,6 @@ - @@ -123,7 +122,6 @@ - @@ -141,7 +139,6 @@ - \ No newline at end of file