| 
					
				 | 
			
			
				@@ -0,0 +1,532 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.IO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.Net; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.Net.Security; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.Net.Sockets; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.Security.Authentication; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.Security.Cryptography.X509Certificates; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.Text; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.Threading; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.Threading.Tasks; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using MediaBrowser.Model.Cryptography; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using MediaBrowser.Model.IO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using MediaBrowser.Model.System; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using Microsoft.Extensions.Logging; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+namespace SocketHttpListener.Net 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    sealed class HttpConnection 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private static AsyncCallback s_onreadCallback = new AsyncCallback(OnRead); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const int BufferSize = 8192; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Socket _socket; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Stream _stream; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        HttpEndPointListener _epl; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        MemoryStream _memoryStream; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        byte[] _buffer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        HttpListenerContext _context; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        StringBuilder _currentLine; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ListenerPrefix _prefix; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        HttpRequestStream _requestStream; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        HttpResponseStream _responseStream; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        bool _chunked; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int _reuses; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        bool _contextBound; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        bool secure; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        IPEndPoint local_ep; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        HttpListener _lastListener; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        X509Certificate cert; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        SslStream ssl_stream; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private readonly ILogger _logger; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private readonly ICryptoProvider _cryptoProvider; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private readonly IStreamHelper _streamHelper; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private readonly IFileSystem _fileSystem; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private readonly IEnvironmentInfo _environment; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public HttpConnection(ILogger logger, Socket socket, HttpEndPointListener epl, bool secure, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            X509Certificate cert, ICryptoProvider cryptoProvider, IStreamHelper streamHelper, IFileSystem fileSystem, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            IEnvironmentInfo environment) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _logger = logger; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this._socket = socket; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this._epl = epl; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.secure = secure; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.cert = cert; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _cryptoProvider = cryptoProvider; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _streamHelper = streamHelper; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _fileSystem = fileSystem; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _environment = environment; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (secure == false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _stream = new SocketStream(_socket, false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ssl_stream = new SslStream(new SocketStream(_socket, false), false, (t, c, ch, e) => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (c == null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    //var c2 = c as X509Certificate2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    //if (c2 == null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    //{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    //    c2 = new X509Certificate2(c.GetRawCertData()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    //} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    //_clientCert = c2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    //_clientCertErrors = new int[] { (int)e }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _stream = ssl_stream; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public Stream Stream => _stream; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public async Task Init() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (ssl_stream != null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var enableAsync = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (enableAsync) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    await ssl_stream.AuthenticateAsServerAsync(cert, false, (SslProtocols)ServicePointManager.SecurityProtocol, false).ConfigureAwait(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    ssl_stream.AuthenticateAsServer(cert, false, (SslProtocols)ServicePointManager.SecurityProtocol, false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            InitInternal(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void InitInternal() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _contextBound = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _requestStream = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _responseStream = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _prefix = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _chunked = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _memoryStream = new MemoryStream(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _position = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _inputState = InputState.RequestLine; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _lineState = LineState.None; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _context = new HttpListenerContext(this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public bool IsClosed => (_socket == null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public int Reuses => _reuses; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public IPEndPoint LocalEndPoint 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            get 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (local_ep != null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return local_ep; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                local_ep = (IPEndPoint)_socket.LocalEndPoint; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return local_ep; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public IPEndPoint RemoteEndPoint => _socket.RemoteEndPoint as IPEndPoint; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public bool IsSecure => secure; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public ListenerPrefix Prefix 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            get => _prefix; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            set => _prefix = value; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void OnTimeout(object unused) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            //_logger.LogInformation("HttpConnection timer fired"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            CloseSocket(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Unbind(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public void BeginReadRequest() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (_buffer == null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _buffer = new byte[BufferSize]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            try 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _stream.BeginRead(_buffer, 0, BufferSize, s_onreadCallback, this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            catch 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                CloseSocket(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Unbind(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public HttpRequestStream GetRequestStream(bool chunked, long contentlength) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (_requestStream == null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                byte[] buffer = _memoryStream.GetBuffer(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                int length = (int)_memoryStream.Length; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _memoryStream = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (chunked) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    _chunked = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    //_context.Response.SendChunked = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    _requestStream = new ChunkedInputStream(_context, _stream, buffer, _position, length - _position); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    _requestStream = new HttpRequestStream(_stream, buffer, _position, length - _position, contentlength); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return _requestStream; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public HttpResponseStream GetResponseStream(bool isExpect100Continue = false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // TODO: can we get this _stream before reading the input? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (_responseStream == null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var supportsDirectSocketAccess = !_context.Response.SendChunked && !isExpect100Continue && !secure; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _responseStream = new HttpResponseStream(_stream, _context.Response, false, _streamHelper, _socket, supportsDirectSocketAccess, _environment, _fileSystem, _logger); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return _responseStream; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private static void OnRead(IAsyncResult ares) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var cnc = (HttpConnection)ares.AsyncState; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            cnc.OnReadInternal(ares); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void OnReadInternal(IAsyncResult ares) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            int nread = -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            try 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                nread = _stream.EndRead(ares); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _memoryStream.Write(_buffer, 0, nread); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (_memoryStream.Length > 32768) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    SendError("Bad Request", 400); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Close(true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            catch 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (_memoryStream != null && _memoryStream.Length > 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    SendError(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (_socket != null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    CloseSocket(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Unbind(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (nread == 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                CloseSocket(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Unbind(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (ProcessInput(_memoryStream)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (!_context.HaveError) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    _context.Request.FinishInitialization(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (_context.HaveError) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    SendError(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Close(true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (!_epl.BindContext(_context)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    const int NotFoundErrorCode = 404; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    SendError(HttpStatusDescription.Get(NotFoundErrorCode), NotFoundErrorCode); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Close(true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                HttpListener listener = _epl.Listener; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (_lastListener != listener) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    RemoveConnection(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    listener.AddConnection(this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    _lastListener = listener; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _contextBound = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                listener.RegisterContext(_context); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _stream.BeginRead(_buffer, 0, BufferSize, s_onreadCallback, this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void RemoveConnection() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (_lastListener == null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _epl.RemoveConnection(this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _lastListener.RemoveConnection(this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private enum InputState 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            RequestLine, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Headers 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private enum LineState 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            None, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            CR, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            LF 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        InputState _inputState = InputState.RequestLine; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        LineState _lineState = LineState.None; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int _position; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // true -> done processing 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // false -> need more input 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private bool ProcessInput(MemoryStream ms) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            byte[] buffer = ms.GetBuffer(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            int len = (int)ms.Length; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            int used = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            string line; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            while (true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (_context.HaveError) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (_position >= len) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                try 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    line = ReadLine(buffer, _position, len - _position, ref used); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    _position += used; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                catch 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    _context.ErrorMessage = "Bad request"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    _context.ErrorStatus = 400; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (line == null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (line == "") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (_inputState == InputState.RequestLine) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    _currentLine = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    ms = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (_inputState == InputState.RequestLine) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    _context.Request.SetRequestLine(line); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    _inputState = InputState.Headers; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    try 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        _context.Request.AddHeader(line); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    catch (Exception e) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        _context.ErrorMessage = e.Message; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        _context.ErrorStatus = 400; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (used == len) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ms.SetLength(0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _position = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private string ReadLine(byte[] buffer, int offset, int len, ref int used) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (_currentLine == null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _currentLine = new StringBuilder(128); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            int last = offset + len; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            used = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for (int i = offset; i < last && _lineState != LineState.LF; i++) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                used++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                byte b = buffer[i]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (b == 13) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    _lineState = LineState.CR; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                else if (b == 10) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    _lineState = LineState.LF; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    _currentLine.Append((char)b); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            string result = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (_lineState == LineState.LF) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _lineState = LineState.None; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                result = _currentLine.ToString(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _currentLine.Length = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return result; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public void SendError(string msg, int status) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            try 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                HttpListenerResponse response = _context.Response; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                response.StatusCode = status; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                response.ContentType = "text/html"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                string description = HttpStatusDescription.Get(status); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                string str; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (msg != null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    str = string.Format("<h1>{0} ({1})</h1>", description, msg); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    str = string.Format("<h1>{0}</h1>", description); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                byte[] error = Encoding.UTF8.GetBytes(str); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                response.Close(error, false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            catch 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // response was already closed 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public void SendError() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            SendError(_context.ErrorMessage, _context.ErrorStatus); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void Unbind() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (_contextBound) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _epl.UnbindContext(_context); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _contextBound = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public void Close() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Close(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void CloseSocket() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (_socket == null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            try 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _socket.Close(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            catch { } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            finally 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _socket = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            RemoveConnection(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        internal void Close(bool force) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (_socket != null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Stream st = GetResponseStream(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (st != null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    st.Close(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _responseStream = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (_socket != null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                force |= !_context.Request.KeepAlive; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (!force) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    force = string.Equals(_context.Response.Headers["connection"], "close", StringComparison.OrdinalIgnoreCase); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (!force && _context.Request.FlushInput()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (_chunked && _context.Response.ForceCloseChunked == false) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        // Don't close. Keep working. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        _reuses++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        Unbind(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        InitInternal(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        BeginReadRequest(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    _reuses++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Unbind(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    InitInternal(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    BeginReadRequest(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Socket s = _socket; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _socket = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                try 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    s?.Shutdown(SocketShutdown.Both); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                catch 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                finally 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    try 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        s?.Close(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    catch { } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Unbind(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                RemoveConnection(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |