Refactored some classes in WebSocketSharp.Net namespace
This commit is contained in:
		@@ -507,6 +507,19 @@ namespace WebSocketSharp {
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal static string Unquote(this string value)
 | 
			
		||||
    {
 | 
			
		||||
      var start = value.IndexOf('\"');
 | 
			
		||||
      var end = value.LastIndexOf('\"');
 | 
			
		||||
      if (start < end)
 | 
			
		||||
      {
 | 
			
		||||
        value = value.Substring(start + 1, end - start - 1)
 | 
			
		||||
                .Replace("\\\"", "\"");
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return value.Trim();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal static void WriteBytes(this Stream stream, byte[] value)
 | 
			
		||||
    {
 | 
			
		||||
      using (var input = new MemoryStream(value))
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
#region License
 | 
			
		||||
//
 | 
			
		||||
// HttpConnection.cs
 | 
			
		||||
//	Copied from System.Net.HttpConnection.cs
 | 
			
		||||
@@ -6,7 +7,7 @@
 | 
			
		||||
//	Gonzalo Paniagua Javier (gonzalo@novell.com)
 | 
			
		||||
//
 | 
			
		||||
// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
 | 
			
		||||
// Copyright (c) 2012 sta.blockhead (sta.blockhead@gmail.com)
 | 
			
		||||
// Copyright (c) 2012-2013 sta.blockhead (sta.blockhead@gmail.com)
 | 
			
		||||
//
 | 
			
		||||
// Permission is hereby granted, free of charge, to any person obtaining
 | 
			
		||||
// a copy of this software and associated documentation files (the
 | 
			
		||||
@@ -27,6 +28,7 @@
 | 
			
		||||
// 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;
 | 
			
		||||
@@ -41,7 +43,7 @@ using WebSocketSharp.Net.Security;
 | 
			
		||||
 | 
			
		||||
namespace WebSocketSharp.Net {
 | 
			
		||||
 | 
			
		||||
	sealed class HttpConnection {
 | 
			
		||||
	internal sealed class HttpConnection {
 | 
			
		||||
 | 
			
		||||
		#region Enums
 | 
			
		||||
 | 
			
		||||
@@ -60,170 +62,176 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
 | 
			
		||||
		#region Private Const Field
 | 
			
		||||
 | 
			
		||||
		const int BufferSize = 8192;
 | 
			
		||||
 | 
			
		||||
		#endregion
 | 
			
		||||
 | 
			
		||||
		#region Private Static Field
 | 
			
		||||
 | 
			
		||||
		static AsyncCallback onread_cb = new AsyncCallback (OnRead);
 | 
			
		||||
		private const int BufferSize = 8192;
 | 
			
		||||
 | 
			
		||||
		#endregion
 | 
			
		||||
 | 
			
		||||
		#region Private Fields
 | 
			
		||||
 | 
			
		||||
		byte []             buffer;
 | 
			
		||||
		bool                chunked;
 | 
			
		||||
		HttpListenerContext context;
 | 
			
		||||
		bool                context_bound;
 | 
			
		||||
		StringBuilder       current_line;
 | 
			
		||||
		EndPointListener    epl;
 | 
			
		||||
		InputState          input_state;
 | 
			
		||||
		RequestStream       i_stream;
 | 
			
		||||
		AsymmetricAlgorithm key;
 | 
			
		||||
		HttpListener        last_listener;
 | 
			
		||||
		LineState           line_state;
 | 
			
		||||
//		IPEndPoint          local_ep; // never used
 | 
			
		||||
		MemoryStream        ms;
 | 
			
		||||
		ResponseStream      o_stream;
 | 
			
		||||
		int                 position;
 | 
			
		||||
		ListenerPrefix      prefix;
 | 
			
		||||
		int                 reuses;
 | 
			
		||||
		bool                secure;
 | 
			
		||||
		Socket              sock;
 | 
			
		||||
		Stream              stream;
 | 
			
		||||
		int                 s_timeout;
 | 
			
		||||
		Timer               timer;
 | 
			
		||||
		private byte []             _buffer;
 | 
			
		||||
		private bool                _chunked;
 | 
			
		||||
		private HttpListenerContext _context;
 | 
			
		||||
		private bool                _contextWasBound;
 | 
			
		||||
		private StringBuilder       _currentLine;
 | 
			
		||||
		private EndPointListener    _epListener;
 | 
			
		||||
		private InputState          _inputState;
 | 
			
		||||
		private RequestStream       _inputStream;
 | 
			
		||||
		private AsymmetricAlgorithm _key;
 | 
			
		||||
		private HttpListener        _lastListener;
 | 
			
		||||
		private LineState           _lineState;
 | 
			
		||||
		private ResponseStream      _outputStream;
 | 
			
		||||
		private int                 _position;
 | 
			
		||||
		private ListenerPrefix      _prefix;
 | 
			
		||||
		private MemoryStream        _requestBuffer;
 | 
			
		||||
		private int                 _reuses;
 | 
			
		||||
		private bool                _secure;
 | 
			
		||||
		private Socket              _socket;
 | 
			
		||||
		private Stream              _stream;
 | 
			
		||||
		private int                 _timeout;
 | 
			
		||||
		private Timer               _timer;
 | 
			
		||||
 | 
			
		||||
		#endregion
 | 
			
		||||
 | 
			
		||||
		#region Constructor
 | 
			
		||||
		#region Public Constructors
 | 
			
		||||
 | 
			
		||||
		public HttpConnection (
 | 
			
		||||
			Socket              sock,
 | 
			
		||||
			EndPointListener    epl,
 | 
			
		||||
			Socket              socket,
 | 
			
		||||
			EndPointListener    listener,
 | 
			
		||||
			bool                secure,
 | 
			
		||||
			X509Certificate2    cert,
 | 
			
		||||
			AsymmetricAlgorithm key
 | 
			
		||||
		)
 | 
			
		||||
			AsymmetricAlgorithm key)
 | 
			
		||||
		{
 | 
			
		||||
			this.sock   = sock;
 | 
			
		||||
			this.epl    = epl;
 | 
			
		||||
			this.secure = secure;
 | 
			
		||||
			this.key    = key;
 | 
			
		||||
//			if (secure == false) {
 | 
			
		||||
//				stream = new NetworkStream (sock, false);
 | 
			
		||||
//			} else {
 | 
			
		||||
//				var ssl_stream = new SslServerStream (new NetworkStream (sock, false), cert, false, false);
 | 
			
		||||
//				ssl_stream.PrivateKeyCertSelectionDelegate += OnPVKSelection;
 | 
			
		||||
//				stream = ssl_stream;
 | 
			
		||||
//			}
 | 
			
		||||
			var net_stream = new NetworkStream (sock, false);
 | 
			
		||||
			_socket = socket;
 | 
			
		||||
			_epListener = listener;
 | 
			
		||||
			_secure = secure;
 | 
			
		||||
			_key = key;
 | 
			
		||||
 | 
			
		||||
			var netStream = new NetworkStream (socket, false);
 | 
			
		||||
			if (!secure) {
 | 
			
		||||
				stream = net_stream;
 | 
			
		||||
				_stream = netStream;
 | 
			
		||||
			} else {
 | 
			
		||||
				var ssl_stream = new SslStream(net_stream, false);
 | 
			
		||||
				ssl_stream.AuthenticateAsServer(cert);
 | 
			
		||||
				stream = ssl_stream;
 | 
			
		||||
				var sslStream = new SslStream (netStream, false);
 | 
			
		||||
				sslStream.AuthenticateAsServer (cert);
 | 
			
		||||
				_stream = sslStream;
 | 
			
		||||
			}
 | 
			
		||||
			timer = new Timer (OnTimeout, null, Timeout.Infinite, Timeout.Infinite);
 | 
			
		||||
 | 
			
		||||
			_timer = new Timer (OnTimeout, null, Timeout.Infinite, Timeout.Infinite);
 | 
			
		||||
			Init ();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		#endregion
 | 
			
		||||
 | 
			
		||||
		#region Properties
 | 
			
		||||
		#region Public Properties
 | 
			
		||||
 | 
			
		||||
		public bool IsClosed {
 | 
			
		||||
			get { return (sock == null); }
 | 
			
		||||
			get {
 | 
			
		||||
				return _socket == null;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool IsSecure {
 | 
			
		||||
			get { return secure; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _secure;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public IPEndPoint LocalEndPoint {
 | 
			
		||||
			get { return (IPEndPoint) sock.LocalEndPoint; }
 | 
			
		||||
			get {
 | 
			
		||||
				return (IPEndPoint) _socket.LocalEndPoint;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public ListenerPrefix Prefix {
 | 
			
		||||
			get { return prefix; }
 | 
			
		||||
			set { prefix = value; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _prefix;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			set {
 | 
			
		||||
				_prefix = value;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public IPEndPoint RemoteEndPoint {
 | 
			
		||||
			get { return (IPEndPoint) sock.RemoteEndPoint; }
 | 
			
		||||
			get {
 | 
			
		||||
				return (IPEndPoint) _socket.RemoteEndPoint;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public int Reuses {
 | 
			
		||||
			get { return reuses; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _reuses;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public Stream Stream {
 | 
			
		||||
			get { return stream; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _stream;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		#endregion
 | 
			
		||||
 | 
			
		||||
		#region Private Methods
 | 
			
		||||
 | 
			
		||||
		void CloseSocket ()
 | 
			
		||||
		private void CloseSocket ()
 | 
			
		||||
		{
 | 
			
		||||
			if (sock == null)
 | 
			
		||||
			if (_socket == null)
 | 
			
		||||
				return;
 | 
			
		||||
 | 
			
		||||
			try {
 | 
			
		||||
				sock.Close ();
 | 
			
		||||
				_socket.Close ();
 | 
			
		||||
			} catch {
 | 
			
		||||
			} finally {
 | 
			
		||||
				sock = null;
 | 
			
		||||
				_socket = null;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			RemoveConnection ();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void Init ()
 | 
			
		||||
		private void Init ()
 | 
			
		||||
		{
 | 
			
		||||
			context_bound = false;
 | 
			
		||||
			i_stream      = null;
 | 
			
		||||
			o_stream      = null;
 | 
			
		||||
			prefix        = null;
 | 
			
		||||
			chunked       = false;
 | 
			
		||||
			ms            = new MemoryStream ();
 | 
			
		||||
			position      = 0;
 | 
			
		||||
			input_state   = InputState.RequestLine;
 | 
			
		||||
			line_state    = LineState.None;
 | 
			
		||||
			context       = new HttpListenerContext (this);
 | 
			
		||||
			s_timeout     = 90000; // 90k ms for first request, 15k ms from then on
 | 
			
		||||
			_chunked = false;
 | 
			
		||||
			_context = new HttpListenerContext (this);
 | 
			
		||||
			_contextWasBound = false;
 | 
			
		||||
			_inputState = InputState.RequestLine;
 | 
			
		||||
			_inputStream = null;
 | 
			
		||||
			_lineState = LineState.None;
 | 
			
		||||
			_outputStream = null;
 | 
			
		||||
			_position = 0;
 | 
			
		||||
			_prefix = null;
 | 
			
		||||
			_requestBuffer = new MemoryStream ();
 | 
			
		||||
			_timeout = 90000; // 90k ms for first request, 15k ms from then on.
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		AsymmetricAlgorithm OnPVKSelection (X509Certificate certificate, string targetHost)
 | 
			
		||||
		private AsymmetricAlgorithm OnPVKSelection (X509Certificate certificate, string targetHost)
 | 
			
		||||
		{
 | 
			
		||||
			return key;
 | 
			
		||||
			return _key;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		static void OnRead (IAsyncResult ares)
 | 
			
		||||
		private static void OnRead (IAsyncResult asyncResult)
 | 
			
		||||
		{
 | 
			
		||||
			HttpConnection cnc = (HttpConnection) ares.AsyncState;
 | 
			
		||||
			cnc.OnReadInternal (ares);
 | 
			
		||||
			var conn = (HttpConnection) asyncResult.AsyncState;
 | 
			
		||||
			conn.OnReadInternal (asyncResult);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void OnReadInternal (IAsyncResult ares)
 | 
			
		||||
		private void OnReadInternal (IAsyncResult asyncResult)
 | 
			
		||||
		{
 | 
			
		||||
			timer.Change (Timeout.Infinite, Timeout.Infinite);
 | 
			
		||||
			int nread = -1;
 | 
			
		||||
			_timer.Change (Timeout.Infinite, Timeout.Infinite);
 | 
			
		||||
			var nread = -1;
 | 
			
		||||
			try {
 | 
			
		||||
				nread = stream.EndRead (ares);
 | 
			
		||||
				ms.Write (buffer, 0, nread);
 | 
			
		||||
				if (ms.Length > 32768) {
 | 
			
		||||
					SendError ("Bad request", 400);
 | 
			
		||||
				nread = _stream.EndRead (asyncResult);
 | 
			
		||||
				_requestBuffer.Write (_buffer, 0, nread);
 | 
			
		||||
				if (_requestBuffer.Length > 32768) {
 | 
			
		||||
					SendError ();
 | 
			
		||||
					Close (true);
 | 
			
		||||
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
			} catch {
 | 
			
		||||
				if (ms != null && ms.Length > 0)
 | 
			
		||||
				if (_requestBuffer != null && _requestBuffer.Length > 0)
 | 
			
		||||
					SendError ();
 | 
			
		||||
 | 
			
		||||
				if (sock != null) {
 | 
			
		||||
				if (_socket != null) {
 | 
			
		||||
					CloseSocket ();
 | 
			
		||||
					Unbind ();
 | 
			
		||||
				}
 | 
			
		||||
@@ -232,156 +240,140 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (nread == 0) {
 | 
			
		||||
				//if (ms.Length > 0)
 | 
			
		||||
				//if (_requestBuffer.Length > 0)
 | 
			
		||||
				//	SendError (); // Why bother?
 | 
			
		||||
				CloseSocket ();
 | 
			
		||||
				Unbind ();
 | 
			
		||||
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (ProcessInput (ms)) {
 | 
			
		||||
				if (!context.HaveError)
 | 
			
		||||
					context.Request.FinishInitialization ();
 | 
			
		||||
			if (ProcessInput (_requestBuffer.GetBuffer ())) {
 | 
			
		||||
				if (!_context.HaveError)
 | 
			
		||||
					_context.Request.FinishInitialization ();
 | 
			
		||||
 | 
			
		||||
				if (context.HaveError) {
 | 
			
		||||
				if (_context.HaveError) {
 | 
			
		||||
					SendError ();
 | 
			
		||||
					Close (true);
 | 
			
		||||
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (!epl.BindContext (context)) {
 | 
			
		||||
				if (!_epListener.BindContext (_context)) {
 | 
			
		||||
					SendError ("Invalid host", 400);
 | 
			
		||||
					Close (true);
 | 
			
		||||
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				HttpListener listener = context.Listener;
 | 
			
		||||
				if (last_listener != listener) {
 | 
			
		||||
				var listener = _context.Listener;
 | 
			
		||||
				if (_lastListener != listener) {
 | 
			
		||||
					RemoveConnection ();
 | 
			
		||||
					listener.AddConnection (this);
 | 
			
		||||
					last_listener = listener;
 | 
			
		||||
					_lastListener = listener;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				context_bound = true;
 | 
			
		||||
				listener.RegisterContext (context);
 | 
			
		||||
				listener.RegisterContext (_context);
 | 
			
		||||
				_contextWasBound = true;
 | 
			
		||||
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			stream.BeginRead (buffer, 0, BufferSize, onread_cb, this);
 | 
			
		||||
			_stream.BeginRead (_buffer, 0, BufferSize, OnRead, this);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void OnTimeout (object unused)
 | 
			
		||||
		private void OnTimeout (object unused)
 | 
			
		||||
		{
 | 
			
		||||
			CloseSocket ();
 | 
			
		||||
			Unbind ();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// true -> done processing
 | 
			
		||||
		// false -> need more input
 | 
			
		||||
		bool ProcessInput (MemoryStream ms)
 | 
			
		||||
		// true -> Done processing.
 | 
			
		||||
		// false -> Need more input.
 | 
			
		||||
		private bool ProcessInput (byte [] data)
 | 
			
		||||
		{
 | 
			
		||||
			byte [] buffer = ms.GetBuffer ();
 | 
			
		||||
			int len = (int) ms.Length;
 | 
			
		||||
			int used = 0;
 | 
			
		||||
			var length = data.Length;
 | 
			
		||||
			var used = 0;
 | 
			
		||||
			string line;
 | 
			
		||||
 | 
			
		||||
			try {
 | 
			
		||||
				line = ReadLine (buffer, position, len - position, ref used);
 | 
			
		||||
				position += used;
 | 
			
		||||
			} catch {
 | 
			
		||||
				context.ErrorMessage = "Bad request";
 | 
			
		||||
				context.ErrorStatus = 400;
 | 
			
		||||
				while ((line = ReadLine (data, _position, length - _position, ref used)) != null) {
 | 
			
		||||
					_position += used;
 | 
			
		||||
					if (line.Length == 0) {
 | 
			
		||||
						if (_inputState == InputState.RequestLine)
 | 
			
		||||
							continue;
 | 
			
		||||
 | 
			
		||||
						_currentLine = null;
 | 
			
		||||
						return true;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					if (_inputState == InputState.RequestLine) {
 | 
			
		||||
						_context.Request.SetRequestLine (line);
 | 
			
		||||
						_inputState = InputState.Headers;
 | 
			
		||||
					} else {
 | 
			
		||||
						_context.Request.AddHeader (line);
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					if (_context.HaveError)
 | 
			
		||||
						return true;
 | 
			
		||||
				}
 | 
			
		||||
			} catch (Exception e) {
 | 
			
		||||
				_context.ErrorMessage = e.Message;
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			do {
 | 
			
		||||
				if (line == null)
 | 
			
		||||
					break;
 | 
			
		||||
				if (line == "") {
 | 
			
		||||
					if (input_state == InputState.RequestLine)
 | 
			
		||||
						continue;
 | 
			
		||||
					current_line = null;
 | 
			
		||||
					ms = null;
 | 
			
		||||
					return true;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (input_state == InputState.RequestLine) {
 | 
			
		||||
					context.Request.SetRequestLine (line);
 | 
			
		||||
					input_state = InputState.Headers;
 | 
			
		||||
				} else {
 | 
			
		||||
					try {
 | 
			
		||||
						context.Request.AddHeader (line);
 | 
			
		||||
					} catch (Exception e) {
 | 
			
		||||
						context.ErrorMessage = e.Message;
 | 
			
		||||
						context.ErrorStatus = 400;
 | 
			
		||||
						return 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;
 | 
			
		||||
				}
 | 
			
		||||
			} while (line != null);
 | 
			
		||||
 | 
			
		||||
			if (used == len) {
 | 
			
		||||
				ms.SetLength (0);
 | 
			
		||||
				position = 0;
 | 
			
		||||
			_position += used;
 | 
			
		||||
			if (used == length) {
 | 
			
		||||
				_requestBuffer.SetLength (0);
 | 
			
		||||
				_position = 0;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		string ReadLine (byte [] buffer, int offset, int len, ref int used)
 | 
			
		||||
		private string ReadLine (byte [] buffer, int offset, int length, ref int used)
 | 
			
		||||
		{
 | 
			
		||||
			if (current_line == null)
 | 
			
		||||
				current_line = new StringBuilder ();
 | 
			
		||||
			if (_currentLine == null)
 | 
			
		||||
				_currentLine = new StringBuilder ();
 | 
			
		||||
 | 
			
		||||
			int last = offset + len;
 | 
			
		||||
			var last = offset + length;
 | 
			
		||||
			used = 0;
 | 
			
		||||
			for (int i = offset; i < last && line_state != LineState.LF; i++) {
 | 
			
		||||
			for (int i = offset; i < last && _lineState != LineState.LF; i++) {
 | 
			
		||||
				used++;
 | 
			
		||||
				byte b = buffer [i];
 | 
			
		||||
				var b = buffer [i];
 | 
			
		||||
				if (b == 13) {
 | 
			
		||||
					line_state = LineState.CR;
 | 
			
		||||
				} else if (b == 10) {
 | 
			
		||||
					line_state = LineState.LF;
 | 
			
		||||
				} else {
 | 
			
		||||
					current_line.Append ((char) b);
 | 
			
		||||
					_lineState = LineState.CR;
 | 
			
		||||
				}
 | 
			
		||||
				else if (b == 10) {
 | 
			
		||||
					_lineState = LineState.LF;
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					_currentLine.Append ((char) b);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			string result = null;
 | 
			
		||||
			if (line_state == LineState.LF) {
 | 
			
		||||
				line_state = LineState.None;
 | 
			
		||||
				result = current_line.ToString ();
 | 
			
		||||
				current_line.Length = 0;
 | 
			
		||||
			if (_lineState == LineState.LF) {
 | 
			
		||||
				_lineState = LineState.None;
 | 
			
		||||
				result = _currentLine.ToString ();
 | 
			
		||||
				_currentLine.Length = 0;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return result;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void RemoveConnection ()
 | 
			
		||||
		private void RemoveConnection ()
 | 
			
		||||
		{
 | 
			
		||||
			if (last_listener == null)
 | 
			
		||||
				epl.RemoveConnection (this);
 | 
			
		||||
			if (_lastListener == null)
 | 
			
		||||
				_epListener.RemoveConnection (this);
 | 
			
		||||
			else
 | 
			
		||||
				last_listener.RemoveConnection (this);
 | 
			
		||||
				_lastListener.RemoveConnection (this);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void Unbind ()
 | 
			
		||||
		private void Unbind ()
 | 
			
		||||
		{
 | 
			
		||||
			if (context_bound) {
 | 
			
		||||
				epl.UnbindContext (context);
 | 
			
		||||
				context_bound = false;
 | 
			
		||||
			if (_contextWasBound) {
 | 
			
		||||
				_epListener.UnbindContext (_context);
 | 
			
		||||
				_contextWasBound = false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -389,49 +381,51 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
 | 
			
		||||
		#region Internal Method
 | 
			
		||||
 | 
			
		||||
		internal void Close (bool force_close)
 | 
			
		||||
		internal void Close (bool force)
 | 
			
		||||
		{
 | 
			
		||||
			if (sock != null) {
 | 
			
		||||
				Stream st = GetResponseStream ();
 | 
			
		||||
				st.Close ();
 | 
			
		||||
				o_stream = null;
 | 
			
		||||
			}
 | 
			
		||||
			if (_socket != null) {
 | 
			
		||||
				if (_outputStream != null) {
 | 
			
		||||
					_outputStream.Close ();
 | 
			
		||||
					_outputStream = null;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			if (sock != null) {
 | 
			
		||||
				force_close |= !context.Request.KeepAlive;
 | 
			
		||||
				if (!force_close)
 | 
			
		||||
					force_close = (context.Response.Headers ["connection"] == "close");
 | 
			
		||||
				force |= !_context.Request.KeepAlive;
 | 
			
		||||
				if (!force)
 | 
			
		||||
					force = _context.Response.Headers ["Connection"] == "close";
 | 
			
		||||
 | 
			
		||||
				if (!force_close && context.Request.FlushInput ()) {
 | 
			
		||||
					if (chunked && context.Response.ForceCloseChunked == false) {
 | 
			
		||||
				if (!force && _context.Request.FlushInput ()) {
 | 
			
		||||
					if (_chunked && !_context.Response.ForceCloseChunked) {
 | 
			
		||||
						// Don't close. Keep working.
 | 
			
		||||
						reuses++;
 | 
			
		||||
						_reuses++;
 | 
			
		||||
						Unbind ();
 | 
			
		||||
						Init ();
 | 
			
		||||
						BeginReadRequest ();
 | 
			
		||||
 | 
			
		||||
						return;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					reuses++;
 | 
			
		||||
					Unbind ();
 | 
			
		||||
					Init ();
 | 
			
		||||
					BeginReadRequest ();
 | 
			
		||||
					return;
 | 
			
		||||
//					_reuses++;
 | 
			
		||||
//					Unbind ();
 | 
			
		||||
//					Init ();
 | 
			
		||||
//					BeginReadRequest ();
 | 
			
		||||
//
 | 
			
		||||
//					return;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				Socket s = sock;
 | 
			
		||||
				sock = null;
 | 
			
		||||
				var socket = _socket;
 | 
			
		||||
				_socket = null;
 | 
			
		||||
				try {
 | 
			
		||||
					if (s != null)
 | 
			
		||||
						s.Shutdown (SocketShutdown.Both);
 | 
			
		||||
					if (socket != null)
 | 
			
		||||
						socket.Shutdown (SocketShutdown.Both);
 | 
			
		||||
				} catch {
 | 
			
		||||
				} finally {
 | 
			
		||||
					if (s != null)
 | 
			
		||||
						s.Close ();
 | 
			
		||||
					if (socket != null)
 | 
			
		||||
						socket.Close ();
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				Unbind ();
 | 
			
		||||
				RemoveConnection ();
 | 
			
		||||
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -442,17 +436,17 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
 | 
			
		||||
		public void BeginReadRequest ()
 | 
			
		||||
		{
 | 
			
		||||
			if (buffer == null)
 | 
			
		||||
				buffer = new byte [BufferSize];
 | 
			
		||||
			if (_buffer == null)
 | 
			
		||||
				_buffer = new byte [BufferSize];
 | 
			
		||||
 | 
			
		||||
			try {
 | 
			
		||||
				if (reuses == 1)
 | 
			
		||||
					s_timeout = 15000;
 | 
			
		||||
				if (_reuses == 1)
 | 
			
		||||
					_timeout = 15000;
 | 
			
		||||
 | 
			
		||||
				timer.Change (s_timeout, Timeout.Infinite);
 | 
			
		||||
				stream.BeginRead (buffer, 0, BufferSize, onread_cb, this);
 | 
			
		||||
				_timer.Change (_timeout, Timeout.Infinite);
 | 
			
		||||
				_stream.BeginRead (_buffer, 0, BufferSize, OnRead, this);
 | 
			
		||||
			} catch {
 | 
			
		||||
				timer.Change (Timeout.Infinite, Timeout.Infinite);
 | 
			
		||||
				_timer.Change (Timeout.Infinite, Timeout.Infinite);
 | 
			
		||||
				CloseSocket ();
 | 
			
		||||
				Unbind ();
 | 
			
		||||
			}
 | 
			
		||||
@@ -465,56 +459,54 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
 | 
			
		||||
		public RequestStream GetRequestStream (bool chunked, long contentlength)
 | 
			
		||||
		{
 | 
			
		||||
			if (i_stream == null) {
 | 
			
		||||
				byte [] buffer = ms.GetBuffer ();
 | 
			
		||||
				int length = (int) ms.Length;
 | 
			
		||||
				ms = null;
 | 
			
		||||
			if (_inputStream == null) {
 | 
			
		||||
				var buffer = _requestBuffer.GetBuffer ();
 | 
			
		||||
				var length = buffer.Length;
 | 
			
		||||
				_requestBuffer = null;
 | 
			
		||||
				if (chunked) {
 | 
			
		||||
					this.chunked = true;
 | 
			
		||||
					context.Response.SendChunked = true;
 | 
			
		||||
					i_stream = new ChunkedInputStream (context, stream, buffer, position, length - position);
 | 
			
		||||
					_chunked = true;
 | 
			
		||||
					_context.Response.SendChunked = true;
 | 
			
		||||
					_inputStream = new ChunkedInputStream (_context, _stream, buffer, _position, length - _position);
 | 
			
		||||
				} else {
 | 
			
		||||
					i_stream = new RequestStream (stream, buffer, position, length - position, contentlength);
 | 
			
		||||
					_inputStream = new RequestStream (_stream, buffer, _position, length - _position, contentlength);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return i_stream;
 | 
			
		||||
			return _inputStream;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public ResponseStream GetResponseStream ()
 | 
			
		||||
		{
 | 
			
		||||
			// TODO: can we get this stream before reading the input?
 | 
			
		||||
			if (o_stream == null) {
 | 
			
		||||
				HttpListener listener = context.Listener;
 | 
			
		||||
				bool ign = (listener == null) ? true : listener.IgnoreWriteExceptions;
 | 
			
		||||
				o_stream = new ResponseStream (stream, context.Response, ign);
 | 
			
		||||
			// TODO: Can we get this stream before reading the input?
 | 
			
		||||
			if (_outputStream == null) {
 | 
			
		||||
				var listener = _context.Listener;
 | 
			
		||||
				var ignore = listener == null ? true : listener.IgnoreWriteExceptions;
 | 
			
		||||
				_outputStream = new ResponseStream (_stream, _context.Response, ignore);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return o_stream;
 | 
			
		||||
			return _outputStream;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void SendError ()
 | 
			
		||||
		{
 | 
			
		||||
			SendError (context.ErrorMessage, context.ErrorStatus);
 | 
			
		||||
			SendError (_context.ErrorMessage, _context.ErrorStatus);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void SendError (string msg, int status)
 | 
			
		||||
		public void SendError (string message, int status)
 | 
			
		||||
		{
 | 
			
		||||
			try {
 | 
			
		||||
				HttpListenerResponse response = context.Response;
 | 
			
		||||
				var response = _context.Response;
 | 
			
		||||
				response.StatusCode = status;
 | 
			
		||||
				response.ContentType = "text/html";
 | 
			
		||||
				string description = status.GetStatusDescription ();
 | 
			
		||||
				string str;
 | 
			
		||||
				if (msg != null)
 | 
			
		||||
					str = String.Format ("<h1>{0} ({1})</h1>", description, msg);
 | 
			
		||||
				else
 | 
			
		||||
					str = String.Format ("<h1>{0}</h1>", description);
 | 
			
		||||
				var description = status.GetStatusDescription ();
 | 
			
		||||
				var error = !message.IsNullOrEmpty ()
 | 
			
		||||
				          ? String.Format ("<h1>{0} ({1})</h1>", description, message)
 | 
			
		||||
				          : String.Format ("<h1>{0}</h1>", description);
 | 
			
		||||
 | 
			
		||||
				byte [] error = context.Response.ContentEncoding.GetBytes (str);
 | 
			
		||||
				response.Close (error, false);
 | 
			
		||||
				var entity = _context.Response.ContentEncoding.GetBytes (error);
 | 
			
		||||
				response.Close (entity, false);
 | 
			
		||||
			} catch {
 | 
			
		||||
				// response was already closed
 | 
			
		||||
				// Response was already closed.
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
#region License
 | 
			
		||||
//
 | 
			
		||||
// HttpListenerContext.cs
 | 
			
		||||
//	Copied from System.Net.HttpListenerContext.cs
 | 
			
		||||
@@ -27,6 +28,7 @@
 | 
			
		||||
// 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.Collections.Specialized;
 | 
			
		||||
@@ -47,12 +49,12 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
 | 
			
		||||
		#region Private Fields
 | 
			
		||||
 | 
			
		||||
		HttpConnection       cnc;
 | 
			
		||||
		string               error;
 | 
			
		||||
		int                  err_status;
 | 
			
		||||
		HttpListenerRequest  request;
 | 
			
		||||
		HttpListenerResponse response;
 | 
			
		||||
		IPrincipal           user;
 | 
			
		||||
		private HttpConnection       _connection;
 | 
			
		||||
		private string               _error;
 | 
			
		||||
		private int                  _errorStatus;
 | 
			
		||||
		private HttpListenerRequest  _request;
 | 
			
		||||
		private HttpListenerResponse _response;
 | 
			
		||||
		private IPrincipal           _user;
 | 
			
		||||
 | 
			
		||||
		#endregion
 | 
			
		||||
 | 
			
		||||
@@ -64,12 +66,12 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
 | 
			
		||||
		#region Constructor
 | 
			
		||||
 | 
			
		||||
		internal HttpListenerContext (HttpConnection cnc)
 | 
			
		||||
		internal HttpListenerContext (HttpConnection connection)
 | 
			
		||||
		{
 | 
			
		||||
			this.cnc   = cnc;
 | 
			
		||||
			err_status = 400;
 | 
			
		||||
			request    = new HttpListenerRequest (this);
 | 
			
		||||
			response   = new HttpListenerResponse (this);
 | 
			
		||||
			_connection = connection;
 | 
			
		||||
			_errorStatus = 400;
 | 
			
		||||
			_request = new HttpListenerRequest (this);
 | 
			
		||||
			_response = new HttpListenerResponse (this);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		#endregion
 | 
			
		||||
@@ -77,21 +79,35 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		#region Internal Properties
 | 
			
		||||
 | 
			
		||||
		internal HttpConnection Connection {
 | 
			
		||||
			get { return cnc; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _connection;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal string ErrorMessage {
 | 
			
		||||
			get { return error; }
 | 
			
		||||
			set { error = value; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _error;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			set {
 | 
			
		||||
				_error = value;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal int ErrorStatus {
 | 
			
		||||
			get { return err_status; }
 | 
			
		||||
			set { err_status = value; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _errorStatus;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			set {
 | 
			
		||||
				_errorStatus = value;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal bool HaveError {
 | 
			
		||||
			get { return (error != null); }
 | 
			
		||||
			get {
 | 
			
		||||
				return _error != null;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		#endregion
 | 
			
		||||
@@ -105,7 +121,9 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		/// A <see cref="HttpListenerRequest"/> that contains the HTTP request objects.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public HttpListenerRequest Request {
 | 
			
		||||
			get { return request; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _request;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -116,7 +134,9 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		/// A <see cref="HttpListenerResponse"/> that contains the HTTP response objects.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public HttpListenerResponse Response {
 | 
			
		||||
			get { return response; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _response;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -126,7 +146,9 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		/// A <see cref="IPrincipal"/> contains the client information.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public IPrincipal User {
 | 
			
		||||
			get { return user; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _user;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		#endregion
 | 
			
		||||
@@ -138,54 +160,40 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
			if (expectedSchemes == AuthenticationSchemes.Anonymous)
 | 
			
		||||
				return;
 | 
			
		||||
 | 
			
		||||
			// TODO: Handle NTLM/Digest modes
 | 
			
		||||
			string header = request.Headers ["Authorization"];
 | 
			
		||||
			// TODO: Handle NTLM/Digest modes.
 | 
			
		||||
			var header = _request.Headers ["Authorization"];
 | 
			
		||||
			if (header == null || header.Length < 2)
 | 
			
		||||
				return;
 | 
			
		||||
 | 
			
		||||
			string [] authenticationData = header.Split (new char [] {' '}, 2);
 | 
			
		||||
			if (string.Compare (authenticationData [0], "basic", true) == 0) {
 | 
			
		||||
				user = ParseBasicAuthentication (authenticationData [1]);
 | 
			
		||||
			}
 | 
			
		||||
			// TODO: throw if malformed -> 400 bad request
 | 
			
		||||
			var authData = header.Split (new char [] {' '}, 2);
 | 
			
		||||
			if (authData [0].ToLower () == "basic")
 | 
			
		||||
				_user = ParseBasicAuthentication (authData [1]);
 | 
			
		||||
 | 
			
		||||
			// TODO: Throw if malformed -> 400 bad request.
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal IPrincipal ParseBasicAuthentication (string authData)
 | 
			
		||||
		{
 | 
			
		||||
			try {
 | 
			
		||||
				// Basic AUTH Data is a formatted Base64 String
 | 
			
		||||
				//string domain = null;
 | 
			
		||||
				string user       = null;
 | 
			
		||||
				string password   = null;
 | 
			
		||||
				int    pos        = -1;
 | 
			
		||||
				string authString = Encoding.Default.GetString (Convert.FromBase64String (authData));
 | 
			
		||||
				// HTTP Basic Authentication data is a formatted Base64 string.
 | 
			
		||||
				var authString = Encoding.Default.GetString (Convert.FromBase64String (authData));
 | 
			
		||||
 | 
			
		||||
				// The format is DOMAIN\username:password
 | 
			
		||||
				// Domain is optional
 | 
			
		||||
				// The format is domain\username:password.
 | 
			
		||||
				// Domain is optional.
 | 
			
		||||
 | 
			
		||||
				pos = authString.IndexOf (':');
 | 
			
		||||
				var pos = authString.IndexOf (':');
 | 
			
		||||
				var user = authString.Substring (0, pos);
 | 
			
		||||
				var password = authString.Substring (pos + 1);
 | 
			
		||||
 | 
			
		||||
				// parse the password off the end
 | 
			
		||||
				password = authString.Substring (pos+1);
 | 
			
		||||
 | 
			
		||||
				// discard the password
 | 
			
		||||
				authString = authString.Substring (0, pos);
 | 
			
		||||
 | 
			
		||||
				// check if there is a domain
 | 
			
		||||
				pos = authString.IndexOf ('\\');
 | 
			
		||||
 | 
			
		||||
				if (pos > 0) {
 | 
			
		||||
					//domain = authString.Substring (0, pos);
 | 
			
		||||
					user = authString.Substring (pos);
 | 
			
		||||
				} else {
 | 
			
		||||
					user = authString;
 | 
			
		||||
				}
 | 
			
		||||
				// Check if there is a domain.
 | 
			
		||||
				pos = user.IndexOf ('\\');
 | 
			
		||||
				if (pos > 0)
 | 
			
		||||
					user = user.Substring (pos + 1);
 | 
			
		||||
 | 
			
		||||
				var identity = new System.Net.HttpListenerBasicIdentity (user, password);
 | 
			
		||||
				// TODO: What are the roles MS sets
 | 
			
		||||
				// TODO: What are the roles MS sets?
 | 
			
		||||
				return new GenericPrincipal (identity, new string [0]);
 | 
			
		||||
			} catch (Exception) {
 | 
			
		||||
				// Invalid auth data is swallowed silently
 | 
			
		||||
			} catch {
 | 
			
		||||
				return null;
 | 
			
		||||
			} 
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
#region License
 | 
			
		||||
//
 | 
			
		||||
// HttpListenerRequest.cs
 | 
			
		||||
//	Copied from System.Net.HttpListenerRequest.cs
 | 
			
		||||
@@ -27,12 +28,14 @@
 | 
			
		||||
// 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.Collections;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Collections.Specialized;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Net;
 | 
			
		||||
using System.Security.Cryptography.X509Certificates;
 | 
			
		||||
using System.Text;
 | 
			
		||||
@@ -49,58 +52,60 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
 | 
			
		||||
		#region Private Static Fields
 | 
			
		||||
 | 
			
		||||
		static char [] separators   = new char [] { ' ' };
 | 
			
		||||
		static byte [] _100continue = Encoding.ASCII.GetBytes ("HTTP/1.1 100 Continue\r\n\r\n");
 | 
			
		||||
		private static byte [] _100continue = Encoding.ASCII.GetBytes ("HTTP/1.1 100 Continue\r\n\r\n");
 | 
			
		||||
 | 
			
		||||
		#endregion
 | 
			
		||||
 | 
			
		||||
		#region Private Fields
 | 
			
		||||
 | 
			
		||||
		string []           accept_types;
 | 
			
		||||
//		int                 client_cert_error;
 | 
			
		||||
		bool                cl_set;
 | 
			
		||||
		Encoding            content_encoding;
 | 
			
		||||
		long                content_length;
 | 
			
		||||
		HttpListenerContext context;
 | 
			
		||||
		CookieCollection    cookies;
 | 
			
		||||
		WebHeaderCollection headers;
 | 
			
		||||
		Stream              input_stream;
 | 
			
		||||
		bool                is_chunked;
 | 
			
		||||
		bool                ka_set;
 | 
			
		||||
		bool                keep_alive;
 | 
			
		||||
		string              method;
 | 
			
		||||
//		bool                no_get_certificate;
 | 
			
		||||
		Version             version;
 | 
			
		||||
		NameValueCollection query_string; // check if null is ok, check if read-only, check case-sensitiveness
 | 
			
		||||
		string              raw_url;
 | 
			
		||||
		Uri                 referrer;
 | 
			
		||||
		Uri                 url;
 | 
			
		||||
		string []           user_languages;
 | 
			
		||||
		private string []           _acceptTypes;
 | 
			
		||||
		private bool                _chunked;
 | 
			
		||||
		private Encoding            _contentEncoding;
 | 
			
		||||
		private long                _contentLength;
 | 
			
		||||
		private bool                _contentLengthWasSet;
 | 
			
		||||
		private HttpListenerContext _context;
 | 
			
		||||
		private CookieCollection    _cookies;
 | 
			
		||||
		private WebHeaderCollection _headers;
 | 
			
		||||
		private Guid                _identifier;
 | 
			
		||||
		private Stream              _inputStream;
 | 
			
		||||
		private bool                _keepAlive;
 | 
			
		||||
		private bool                _keepAliveWasSet;
 | 
			
		||||
		private string              _method;
 | 
			
		||||
		private NameValueCollection _queryString;
 | 
			
		||||
		private string              _rawUrl;
 | 
			
		||||
		private Uri                 _referer;
 | 
			
		||||
		private Uri                 _url;
 | 
			
		||||
		private string []           _userLanguages;
 | 
			
		||||
		private Version             _version;
 | 
			
		||||
 | 
			
		||||
		#endregion
 | 
			
		||||
 | 
			
		||||
		#region Constructor
 | 
			
		||||
		#region Internal Constructors
 | 
			
		||||
 | 
			
		||||
		internal HttpListenerRequest (HttpListenerContext context)
 | 
			
		||||
		{
 | 
			
		||||
			this.context = context;
 | 
			
		||||
			headers = new WebHeaderCollection ();
 | 
			
		||||
			version = HttpVersion.Version10;
 | 
			
		||||
			_context = context;
 | 
			
		||||
			_contentLength = -1;
 | 
			
		||||
			_headers = new WebHeaderCollection ();
 | 
			
		||||
			_identifier = Guid.NewGuid ();
 | 
			
		||||
			_version = HttpVersion.Version10;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		#endregion
 | 
			
		||||
 | 
			
		||||
		#region Properties
 | 
			
		||||
		#region Public Properties
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Gets the media types which are acceptable for the response.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		/// <value>
 | 
			
		||||
		/// An array of <see cref="string"/> that contains the media type names in the Accept request-header field
 | 
			
		||||
		/// An array of <see cref="string"/> that contains the media type names in the Accept request-header
 | 
			
		||||
		/// or <see langword="null"/> if the request did not include an Accept header.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public string [] AcceptTypes {
 | 
			
		||||
			get { return accept_types; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _acceptTypes;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -110,12 +115,13 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		/// Always returns <c>0</c>.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public int ClientCertificateError {
 | 
			
		||||
			// TODO: Always returns 0
 | 
			
		||||
			get {
 | 
			
		||||
				// TODO: Always returns 0.
 | 
			
		||||
/*
 | 
			
		||||
				if (no_get_certificate)
 | 
			
		||||
					throw new InvalidOperationException (
 | 
			
		||||
						"Call GetClientCertificate() before calling this method.");
 | 
			
		||||
						"Call GetClientCertificate method before accessing this property.");
 | 
			
		||||
 | 
			
		||||
				return client_cert_error;
 | 
			
		||||
*/
 | 
			
		||||
				return 0;
 | 
			
		||||
@@ -123,17 +129,18 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Gets the encoding that can be used with the entity body data included in the request.
 | 
			
		||||
		/// Gets the encoding used with the entity body data included in the request.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		/// <value>
 | 
			
		||||
		/// A <see cref="Encoding"/> that contains the encoding that can be used with the entity body data.
 | 
			
		||||
		/// A <see cref="Encoding"/> that indicates the encoding used with the entity body data
 | 
			
		||||
		/// or <see cref="Encoding.Default"/> if the request did not include the information about the encoding.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public Encoding ContentEncoding {
 | 
			
		||||
			// TODO: Always returns Encoding.Default
 | 
			
		||||
			get {
 | 
			
		||||
				if (content_encoding == null)
 | 
			
		||||
					content_encoding = Encoding.Default;
 | 
			
		||||
				return content_encoding;
 | 
			
		||||
				if (_contentEncoding == null)
 | 
			
		||||
					_contentEncoding = Encoding.Default;
 | 
			
		||||
 | 
			
		||||
				return _contentEncoding;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -141,21 +148,25 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		/// Gets the size of the entity body data included in the request.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		/// <value>
 | 
			
		||||
		/// A <see cref="long"/> that contains the value of the Content-Length entity-header field.
 | 
			
		||||
		/// A <see cref="long"/> that contains the value of the Content-Length entity-header.
 | 
			
		||||
		/// The value is a number of bytes in the entity body data. <c>-1</c> if the size is not known.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public long ContentLength64 {
 | 
			
		||||
			get { return content_length; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _contentLength;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Gets the media type of the entity body included in the request.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		/// <value>
 | 
			
		||||
		/// A <see cref="string"/> that contains the value of the Content-Type entity-header field.
 | 
			
		||||
		/// A <see cref="string"/> that contains the value of the Content-Type entity-header.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public string ContentType {
 | 
			
		||||
			get { return headers ["content-type"]; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _headers ["Content-Type"];
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -166,10 +177,10 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public CookieCollection Cookies {
 | 
			
		||||
			get {
 | 
			
		||||
				// TODO: check if the collection is read-only
 | 
			
		||||
				if (cookies == null)
 | 
			
		||||
					cookies = new CookieCollection ();
 | 
			
		||||
				return cookies;
 | 
			
		||||
				if (_cookies == null)
 | 
			
		||||
					_cookies = _headers.GetCookies (false);
 | 
			
		||||
 | 
			
		||||
				return _cookies;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -180,7 +191,9 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		/// <c>true</c> if the request has the entity body; otherwise, <c>false</c>.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public bool HasEntityBody {
 | 
			
		||||
			get { return (content_length > 0 || is_chunked); }
 | 
			
		||||
			get {
 | 
			
		||||
				return _contentLength > 0 || _chunked;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -190,7 +203,9 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		/// A <see cref="NameValueCollection"/> that contains the HTTP headers used in the request.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public NameValueCollection Headers {
 | 
			
		||||
			get { return headers; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _headers;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -200,7 +215,9 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		/// A <see cref="string"/> that contains the HTTP method used in the request.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public string HttpMethod {
 | 
			
		||||
			get { return method; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _method;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -211,14 +228,12 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public Stream InputStream {
 | 
			
		||||
			get {
 | 
			
		||||
				if (input_stream == null) {
 | 
			
		||||
					if (is_chunked || content_length > 0)
 | 
			
		||||
						input_stream = context.Connection.GetRequestStream (is_chunked, content_length);
 | 
			
		||||
					else
 | 
			
		||||
						input_stream = Stream.Null;
 | 
			
		||||
				}
 | 
			
		||||
				if (_inputStream == null)
 | 
			
		||||
					_inputStream = HasEntityBody
 | 
			
		||||
					             ? _context.Connection.GetRequestStream (_chunked, _contentLength)
 | 
			
		||||
					             : Stream.Null;
 | 
			
		||||
 | 
			
		||||
				return input_stream;
 | 
			
		||||
				return _inputStream;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -229,8 +244,10 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		/// Always returns <c>false</c>.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public bool IsAuthenticated {
 | 
			
		||||
			// TODO: Always returns false
 | 
			
		||||
			get { return false; }
 | 
			
		||||
			get {
 | 
			
		||||
				// TODO: Always returns false.
 | 
			
		||||
				return false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -240,7 +257,9 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		/// <c>true</c> if the request is sent from the local computer; otherwise, <c>false</c>.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public bool IsLocal {
 | 
			
		||||
			get { return RemoteEndPoint.Address.IsLocal(); }
 | 
			
		||||
			get {
 | 
			
		||||
				return RemoteEndPoint.Address.IsLocal ();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -250,7 +269,9 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		/// <c>true</c> if the HTTP connection is secured; otherwise, <c>false</c>.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public bool IsSecureConnection {
 | 
			
		||||
			get { return context.Connection.IsSecure; } 
 | 
			
		||||
			get {
 | 
			
		||||
				return _context.Connection.IsSecure;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -261,19 +282,19 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public bool IsWebSocketRequest {
 | 
			
		||||
			get {
 | 
			
		||||
				return method != "GET"
 | 
			
		||||
				return _method != "GET"
 | 
			
		||||
					? false
 | 
			
		||||
					: version < HttpVersion.Version11
 | 
			
		||||
					: _version < HttpVersion.Version11
 | 
			
		||||
						? false
 | 
			
		||||
						: !headers.Contains("Upgrade", "websocket")
 | 
			
		||||
						: !_headers.Contains("Upgrade", "websocket")
 | 
			
		||||
							? false
 | 
			
		||||
							: !headers.Contains("Connection", "Upgrade")
 | 
			
		||||
							: !_headers.Contains("Connection", "Upgrade")
 | 
			
		||||
								? false
 | 
			
		||||
								: !headers.Contains("Host")
 | 
			
		||||
								: !_headers.Contains("Host")
 | 
			
		||||
									? false
 | 
			
		||||
									: !headers.Contains("Sec-WebSocket-Key")
 | 
			
		||||
									: !_headers.Contains("Sec-WebSocket-Key")
 | 
			
		||||
										? false
 | 
			
		||||
										: headers.Contains("Sec-WebSocket-Version");
 | 
			
		||||
										: _headers.Contains("Sec-WebSocket-Version");
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -285,24 +306,17 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public bool KeepAlive {
 | 
			
		||||
			get {
 | 
			
		||||
				if (ka_set)
 | 
			
		||||
					return keep_alive;
 | 
			
		||||
				if (!_keepAliveWasSet) {
 | 
			
		||||
					_keepAlive = _headers.Contains ("Connection", "keep-alive") || _version == HttpVersion.Version11
 | 
			
		||||
					           ? true
 | 
			
		||||
					           : _headers.Contains ("Keep-Alive")
 | 
			
		||||
					             ? !_headers.Contains ("Keep-Alive", "closed")
 | 
			
		||||
					             : false;
 | 
			
		||||
 | 
			
		||||
				ka_set = true;
 | 
			
		||||
				// 1. Connection header
 | 
			
		||||
				// 2. Protocol (1.1 == keep-alive by default)
 | 
			
		||||
				// 3. Keep-Alive header
 | 
			
		||||
				string cnc = headers ["Connection"];
 | 
			
		||||
				if (!String.IsNullOrEmpty (cnc)) {
 | 
			
		||||
					keep_alive = (0 == String.Compare (cnc, "keep-alive", StringComparison.OrdinalIgnoreCase));
 | 
			
		||||
				} else if (version == HttpVersion.Version11) {
 | 
			
		||||
					keep_alive = true;
 | 
			
		||||
				} else {
 | 
			
		||||
					cnc = headers ["keep-alive"];
 | 
			
		||||
					if (!String.IsNullOrEmpty (cnc))
 | 
			
		||||
						keep_alive = (0 != String.Compare (cnc, "closed", StringComparison.OrdinalIgnoreCase));
 | 
			
		||||
					_keepAliveWasSet = true;
 | 
			
		||||
				}
 | 
			
		||||
				return keep_alive;
 | 
			
		||||
 | 
			
		||||
				return _keepAlive;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -313,7 +327,9 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		/// A <see cref="IPEndPoint"/> that contains the server endpoint.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public IPEndPoint LocalEndPoint {
 | 
			
		||||
			get { return context.Connection.LocalEndPoint; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _context.Connection.LocalEndPoint;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -323,7 +339,9 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		/// A <see cref="Version"/> that contains the HTTP version used in the request.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public Version ProtocolVersion {
 | 
			
		||||
			get { return version; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _version;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -333,7 +351,9 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		/// A <see cref="NameValueCollection"/> that contains the collection of query string variables used in the request.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public NameValueCollection QueryString {
 | 
			
		||||
			get { return query_string; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _queryString;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -343,7 +363,9 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		/// A <see cref="string"/> that contains the raw URL requested by the client.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public string RawUrl {
 | 
			
		||||
			get { return raw_url; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _rawUrl;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -353,18 +375,21 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		/// A <see cref="IPEndPoint"/> that contains the client endpoint.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public IPEndPoint RemoteEndPoint {
 | 
			
		||||
			get { return context.Connection.RemoteEndPoint; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _context.Connection.RemoteEndPoint;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Gets the identifier of a request.
 | 
			
		||||
		/// Gets the request identifier of a incoming HTTP request.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		/// <value>
 | 
			
		||||
		/// A <see cref="Guid"/> that contains the identifier of a request.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public Guid RequestTraceIdentifier {
 | 
			
		||||
			// TODO: Always returns Guid.Empty
 | 
			
		||||
			get { return Guid.Empty; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _identifier;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -374,27 +399,34 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		/// A <see cref="Uri"/> that contains the URL requested by the client.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public Uri Url {
 | 
			
		||||
			get { return url; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _url;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Gets the URL of the resource from which the requested URL was obtained.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		/// <value>
 | 
			
		||||
		/// A <see cref="Uri"/> that contains the value of the Referer request-header field.
 | 
			
		||||
		/// A <see cref="Uri"/> that contains the value of the Referer request-header
 | 
			
		||||
		/// or <see langword="null"/> if the request did not include an Referer header.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public Uri UrlReferrer {
 | 
			
		||||
			get { return referrer; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _referer;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Gets the information about the user agent originating the request.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		/// <value>
 | 
			
		||||
		/// A <see cref="string"/> that contains the value of the User-Agent request-header field.
 | 
			
		||||
		/// A <see cref="string"/> that contains the value of the User-Agent request-header.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public string UserAgent {
 | 
			
		||||
			get { return headers ["user-agent"]; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _headers ["User-Agent"];
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
@@ -404,52 +436,60 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
		/// A <see cref="string"/> that contains the server endpoint.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public string UserHostAddress {
 | 
			
		||||
			get { return LocalEndPoint.ToString (); }
 | 
			
		||||
			get {
 | 
			
		||||
				return LocalEndPoint.ToString ();
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Gets the internet host name and port number (if present) of the resource being requested.
 | 
			
		||||
		/// Gets the internet host name and port number (if present) specified by the client.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		/// <value>
 | 
			
		||||
		/// A <see cref="string"/> that contains the value of the Host request-header field.
 | 
			
		||||
		/// A <see cref="string"/> that contains the value of the Host request-header.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public string UserHostName {
 | 
			
		||||
			get { return headers ["host"]; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _headers ["Host"];
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/// <summary>
 | 
			
		||||
		/// Gets the natural languages that are preferred as a response to the request.
 | 
			
		||||
		/// Gets the natural languages which are preferred for the response.
 | 
			
		||||
		/// </summary>
 | 
			
		||||
		/// <value>
 | 
			
		||||
		/// An array of <see cref="string"/> that contains the natural language names in the Accept-Language request-header field.
 | 
			
		||||
		/// An array of <see cref="string"/> that contains the natural language names in the Accept-Language request-header
 | 
			
		||||
		/// or <see langword="null"/> if the request did not include an Accept-Language header.
 | 
			
		||||
		/// </value>
 | 
			
		||||
		public string [] UserLanguages {
 | 
			
		||||
			get { return user_languages; }
 | 
			
		||||
			get {
 | 
			
		||||
				return _userLanguages;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		#endregion
 | 
			
		||||
 | 
			
		||||
		#region Private Methods
 | 
			
		||||
 | 
			
		||||
		void CreateQueryString (string query)
 | 
			
		||||
		private void CreateQueryString (string query)
 | 
			
		||||
		{
 | 
			
		||||
			if (query == null || query.Length == 0) {
 | 
			
		||||
				query_string = new NameValueCollection (1);
 | 
			
		||||
				_queryString = new NameValueCollection (1);
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			query_string = new NameValueCollection ();
 | 
			
		||||
			_queryString = new NameValueCollection ();
 | 
			
		||||
			if (query [0] == '?')
 | 
			
		||||
				query = query.Substring (1);
 | 
			
		||||
			string [] components = query.Split ('&');
 | 
			
		||||
			foreach (string kv in components) {
 | 
			
		||||
				int pos = kv.IndexOf ('=');
 | 
			
		||||
 | 
			
		||||
			var components = query.Split ('&');
 | 
			
		||||
			foreach (var kv in components) {
 | 
			
		||||
				var pos = kv.IndexOf ('=');
 | 
			
		||||
				if (pos == -1) {
 | 
			
		||||
					query_string.Add (null, HttpUtility.UrlDecode (kv));
 | 
			
		||||
					_queryString.Add (null, HttpUtility.UrlDecode (kv));
 | 
			
		||||
				} else {
 | 
			
		||||
					string key = HttpUtility.UrlDecode (kv.Substring (0, pos));
 | 
			
		||||
					string val = HttpUtility.UrlDecode (kv.Substring (pos + 1));
 | 
			
		||||
					query_string.Add (key, val);
 | 
			
		||||
					var key = HttpUtility.UrlDecode (kv.Substring (0, pos));
 | 
			
		||||
					var val = HttpUtility.UrlDecode (kv.Substring (pos + 1));
 | 
			
		||||
					_queryString.Add (key, val);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -460,164 +500,143 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
 | 
			
		||||
		internal void AddHeader (string header)
 | 
			
		||||
		{
 | 
			
		||||
			int colon = header.IndexOf (':');
 | 
			
		||||
			if (colon == -1 || colon == 0) {
 | 
			
		||||
				context.ErrorMessage = "Bad Request";
 | 
			
		||||
				context.ErrorStatus = 400;
 | 
			
		||||
			var colon = header.IndexOf (':');
 | 
			
		||||
			if (colon <= 0) {
 | 
			
		||||
				_context.ErrorMessage = "Invalid header";
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			string name = header.Substring (0, colon).Trim ();
 | 
			
		||||
			string val = header.Substring (colon + 1).Trim ();
 | 
			
		||||
			string lower = name.ToLower (CultureInfo.InvariantCulture);
 | 
			
		||||
			headers.SetInternal (name, val, false);
 | 
			
		||||
			switch (lower) {
 | 
			
		||||
				case "accept-language":
 | 
			
		||||
					user_languages = val.Split (','); // yes, only split with a ','
 | 
			
		||||
					break;
 | 
			
		||||
				case "accept":
 | 
			
		||||
					accept_types = val.Split (','); // yes, only split with a ','
 | 
			
		||||
					break;
 | 
			
		||||
				case "content-length":
 | 
			
		||||
					try {
 | 
			
		||||
						//TODO: max. content_length?
 | 
			
		||||
						content_length = Int64.Parse (val.Trim ());
 | 
			
		||||
						if (content_length < 0)
 | 
			
		||||
							context.ErrorMessage = "Invalid Content-Length.";
 | 
			
		||||
						cl_set = true;
 | 
			
		||||
					} catch {
 | 
			
		||||
						context.ErrorMessage = "Invalid Content-Length.";
 | 
			
		||||
					}
 | 
			
		||||
			var name = header.Substring (0, colon).Trim ();
 | 
			
		||||
			var val = header.Substring (colon + 1).Trim ();
 | 
			
		||||
			var lower = name.ToLower (CultureInfo.InvariantCulture);
 | 
			
		||||
			_headers.SetInternal (name, val, false);
 | 
			
		||||
 | 
			
		||||
					break;
 | 
			
		||||
				case "referer":
 | 
			
		||||
					try {
 | 
			
		||||
						referrer = new Uri (val);
 | 
			
		||||
					} catch {
 | 
			
		||||
						referrer = new Uri ("http://someone.is.screwing.with.the.headers.com/");
 | 
			
		||||
					}
 | 
			
		||||
					break;
 | 
			
		||||
				case "cookie":
 | 
			
		||||
					if (cookies == null)
 | 
			
		||||
						cookies = new CookieCollection();
 | 
			
		||||
 | 
			
		||||
					string[] cookieStrings = val.Split(new char[] {',', ';'});
 | 
			
		||||
					Cookie current = null;
 | 
			
		||||
					int version = 0;
 | 
			
		||||
					foreach (string cookieString in cookieStrings) {
 | 
			
		||||
						string str = cookieString.Trim ();
 | 
			
		||||
						if (str.Length == 0)
 | 
			
		||||
							continue;
 | 
			
		||||
						if (str.StartsWith ("$Version")) {
 | 
			
		||||
							version = Int32.Parse (Unquote (str.Substring (str.IndexOf ('=') + 1)));
 | 
			
		||||
						} else if (str.StartsWith ("$Path")) {
 | 
			
		||||
							if (current != null)
 | 
			
		||||
								current.Path = str.Substring (str.IndexOf ('=') + 1).Trim ();
 | 
			
		||||
						} else if (str.StartsWith ("$Domain")) {
 | 
			
		||||
							if (current != null)
 | 
			
		||||
								current.Domain = str.Substring (str.IndexOf ('=') + 1).Trim ();
 | 
			
		||||
						} else if (str.StartsWith ("$Port")) {
 | 
			
		||||
							if (current != null)
 | 
			
		||||
								current.Port = str.Substring (str.IndexOf ('=') + 1).Trim ();
 | 
			
		||||
						} else {
 | 
			
		||||
							if (current != null) {
 | 
			
		||||
								cookies.Add (current);
 | 
			
		||||
							}
 | 
			
		||||
							current = new Cookie ();
 | 
			
		||||
							int idx = str.IndexOf ('=');
 | 
			
		||||
							if (idx > 0) {
 | 
			
		||||
								current.Name = str.Substring (0, idx).Trim ();
 | 
			
		||||
								current.Value =  str.Substring (idx + 1).Trim ();
 | 
			
		||||
							} else {
 | 
			
		||||
								current.Name = str.Trim ();
 | 
			
		||||
								current.Value = String.Empty;
 | 
			
		||||
							}
 | 
			
		||||
							current.Version = version;
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					if (current != null) {
 | 
			
		||||
						cookies.Add (current);
 | 
			
		||||
					}
 | 
			
		||||
					break;
 | 
			
		||||
			if (lower == "accept") {
 | 
			
		||||
				_acceptTypes = val.SplitHeaderValue (',').ToArray ();
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (lower == "accept-language") {
 | 
			
		||||
				_userLanguages = val.Split (',');
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (lower == "content-length") {
 | 
			
		||||
				long length;
 | 
			
		||||
				if (Int64.TryParse (val, out length) && length >= 0) {
 | 
			
		||||
					_contentLength = length;
 | 
			
		||||
					_contentLengthWasSet = true;
 | 
			
		||||
				} else {
 | 
			
		||||
					_context.ErrorMessage = "Invalid Content-Length header";
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (lower == "content-type") {
 | 
			
		||||
				var contents = val.Split (';');
 | 
			
		||||
				foreach (var content in contents) {
 | 
			
		||||
					var tmp = content.Trim ();
 | 
			
		||||
					if (tmp.StartsWith ("charset")) {
 | 
			
		||||
						var charset = tmp.GetValue ("=");
 | 
			
		||||
						if (!charset.IsNullOrEmpty ()) {
 | 
			
		||||
							try {
 | 
			
		||||
								_contentEncoding = Encoding.GetEncoding (charset);
 | 
			
		||||
							} catch {
 | 
			
		||||
								_context.ErrorMessage = "Invalid Content-Type header";
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
						break;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (lower == "referer")
 | 
			
		||||
				_referer = val.ToUri ();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal void FinishInitialization ()
 | 
			
		||||
		{
 | 
			
		||||
			string host = UserHostName;
 | 
			
		||||
			if (version > HttpVersion.Version10 && (host == null || host.Length == 0)) {
 | 
			
		||||
				context.ErrorMessage = "Invalid host name";
 | 
			
		||||
			var host = UserHostName;
 | 
			
		||||
			if (_version > HttpVersion.Version10 && host.IsNullOrEmpty ()) {
 | 
			
		||||
				_context.ErrorMessage = "Invalid Host header";
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			string path;
 | 
			
		||||
			Uri raw_uri = null;
 | 
			
		||||
			if (raw_url.MaybeUri () && Uri.TryCreate (raw_url, UriKind.Absolute, out raw_uri))
 | 
			
		||||
				path = raw_uri.PathAndQuery;
 | 
			
		||||
			else
 | 
			
		||||
				path = HttpUtility.UrlDecode (raw_url);
 | 
			
		||||
			Uri rawUri = null;
 | 
			
		||||
			var path = _rawUrl.MaybeUri () && Uri.TryCreate (_rawUrl, UriKind.Absolute, out rawUri)
 | 
			
		||||
			         ? rawUri.PathAndQuery
 | 
			
		||||
			         : HttpUtility.UrlDecode (_rawUrl);
 | 
			
		||||
 | 
			
		||||
			if ((host == null || host.Length == 0))
 | 
			
		||||
			if (host.IsNullOrEmpty ())
 | 
			
		||||
				host = UserHostAddress;
 | 
			
		||||
 | 
			
		||||
			if (raw_uri != null)
 | 
			
		||||
				host = raw_uri.Host;
 | 
			
		||||
			if (rawUri != null)
 | 
			
		||||
				host = rawUri.Host;
 | 
			
		||||
 | 
			
		||||
			int colon = host.IndexOf (':');
 | 
			
		||||
			var colon = host.IndexOf (':');
 | 
			
		||||
			if (colon >= 0)
 | 
			
		||||
				host = host.Substring (0, colon);
 | 
			
		||||
 | 
			
		||||
			string base_uri = String.Format ("{0}://{1}:{2}",
 | 
			
		||||
								(IsSecureConnection) ? "https" : "http",
 | 
			
		||||
								host,
 | 
			
		||||
								LocalEndPoint.Port);
 | 
			
		||||
			var baseUri = String.Format ("{0}://{1}:{2}",
 | 
			
		||||
				IsSecureConnection ? "https" : "http",
 | 
			
		||||
				host,
 | 
			
		||||
				LocalEndPoint.Port);
 | 
			
		||||
 | 
			
		||||
			if (!Uri.TryCreate (base_uri + path, UriKind.Absolute, out url)){
 | 
			
		||||
				context.ErrorMessage = "Invalid url: " + base_uri + path;
 | 
			
		||||
			if (!Uri.TryCreate (baseUri + path, UriKind.Absolute, out _url)) {
 | 
			
		||||
				_context.ErrorMessage = "Invalid request url: " + baseUri + path;
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			CreateQueryString (url.Query);
 | 
			
		||||
			CreateQueryString (_url.Query);
 | 
			
		||||
 | 
			
		||||
			if (version >= HttpVersion.Version11) {
 | 
			
		||||
				string t_encoding = Headers ["Transfer-Encoding"];
 | 
			
		||||
				is_chunked = (t_encoding != null && String.Compare (t_encoding, "chunked", StringComparison.OrdinalIgnoreCase) == 0);
 | 
			
		||||
			var encoding = Headers ["Transfer-Encoding"];
 | 
			
		||||
			if (_version >= HttpVersion.Version11 && !encoding.IsNullOrEmpty ()) {
 | 
			
		||||
				_chunked = encoding.ToLower () == "chunked";
 | 
			
		||||
				// 'identity' is not valid!
 | 
			
		||||
				if (t_encoding != null && !is_chunked) {
 | 
			
		||||
					context.Connection.SendError (null, 501);
 | 
			
		||||
				if (!_chunked) {
 | 
			
		||||
					_context.ErrorMessage = String.Empty;
 | 
			
		||||
					_context.ErrorStatus = 501;
 | 
			
		||||
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (!is_chunked && !cl_set) {
 | 
			
		||||
				if (String.Compare (method, "POST", StringComparison.OrdinalIgnoreCase) == 0 ||
 | 
			
		||||
				    String.Compare (method, "PUT", StringComparison.OrdinalIgnoreCase) == 0) {
 | 
			
		||||
					context.Connection.SendError (null, 411);
 | 
			
		||||
			if (!_chunked && !_contentLengthWasSet) {
 | 
			
		||||
				var method = _method.ToLower ();
 | 
			
		||||
				if (method == "post" || method == "put") {
 | 
			
		||||
					_context.ErrorMessage = String.Empty;
 | 
			
		||||
					_context.ErrorStatus = 411;
 | 
			
		||||
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (String.Compare (Headers ["Expect"], "100-continue", StringComparison.OrdinalIgnoreCase) == 0) {
 | 
			
		||||
				ResponseStream output = context.Connection.GetResponseStream ();
 | 
			
		||||
			var expect = Headers ["Expect"];
 | 
			
		||||
			if (!expect.IsNullOrEmpty () && expect.ToLower () == "100-continue") {
 | 
			
		||||
				var output = _context.Connection.GetResponseStream ();
 | 
			
		||||
				output.InternalWrite (_100continue, 0, _100continue.Length);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// returns true is the stream could be reused.
 | 
			
		||||
		// Returns true is the stream could be reused.
 | 
			
		||||
		internal bool FlushInput ()
 | 
			
		||||
		{
 | 
			
		||||
			if (!HasEntityBody)
 | 
			
		||||
				return true;
 | 
			
		||||
 | 
			
		||||
			int length = 2048;
 | 
			
		||||
			if (content_length > 0)
 | 
			
		||||
				length = (int) Math.Min (content_length, (long) length);
 | 
			
		||||
			var length = 2048;
 | 
			
		||||
			if (_contentLength > 0)
 | 
			
		||||
				length = (int) Math.Min (_contentLength, (long) length);
 | 
			
		||||
 | 
			
		||||
			byte [] bytes = new byte [length];
 | 
			
		||||
			var buffer = new byte [length];
 | 
			
		||||
			while (true) {
 | 
			
		||||
				// TODO: test if MS has a timeout when doing this
 | 
			
		||||
				// TODO: Test if MS has a timeout when doing this.
 | 
			
		||||
				try {
 | 
			
		||||
					IAsyncResult ares = InputStream.BeginRead (bytes, 0, length, null, null);
 | 
			
		||||
					var ares = InputStream.BeginRead (buffer, 0, length, null, null);
 | 
			
		||||
					if (!ares.IsCompleted && !ares.AsyncWaitHandle.WaitOne (100))
 | 
			
		||||
						return false;
 | 
			
		||||
 | 
			
		||||
@@ -629,54 +648,36 @@ namespace WebSocketSharp.Net {
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal void SetRequestLine (string req)
 | 
			
		||||
		internal void SetRequestLine (string requestLine)
 | 
			
		||||
		{
 | 
			
		||||
			string [] parts = req.Split (separators, 3);
 | 
			
		||||
			var parts = requestLine.Split (new char [] { ' ' }, 3);
 | 
			
		||||
			if (parts.Length != 3) {
 | 
			
		||||
				context.ErrorMessage = "Invalid request line (parts).";
 | 
			
		||||
				_context.ErrorMessage = "Invalid request line (parts)";
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			method = parts [0];
 | 
			
		||||
			foreach (char c in method){
 | 
			
		||||
				int ic = (int) c;
 | 
			
		||||
 | 
			
		||||
				if ((ic >= 'A' && ic <= 'Z') ||
 | 
			
		||||
				    (ic > 32 && c < 127 && c != '(' && c != ')' && c != '<' &&
 | 
			
		||||
				     c != '<' && c != '>' && c != '@' && c != ',' && c != ';' &&
 | 
			
		||||
				     c != ':' && c != '\\' && c != '"' && c != '/' && c != '[' &&
 | 
			
		||||
				     c != ']' && c != '?' && c != '=' && c != '{' && c != '}'))
 | 
			
		||||
					continue;
 | 
			
		||||
 | 
			
		||||
				context.ErrorMessage = "(Invalid verb)";
 | 
			
		||||
			_method = parts [0];
 | 
			
		||||
			if (!_method.IsToken ()) {
 | 
			
		||||
				_context.ErrorMessage = "Invalid request line (method)";
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			raw_url = parts [1];
 | 
			
		||||
			_rawUrl = parts [1];
 | 
			
		||||
 | 
			
		||||
			if (parts [2].Length != 8 || !parts [2].StartsWith ("HTTP/")) {
 | 
			
		||||
				context.ErrorMessage = "Invalid request line (version).";
 | 
			
		||||
				_context.ErrorMessage = "Invalid request line (version)";
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			try {
 | 
			
		||||
				version = new Version (parts [2].Substring (5));
 | 
			
		||||
				if (version.Major < 1)
 | 
			
		||||
				_version = new Version (parts [2].Substring (5));
 | 
			
		||||
				if (_version.Major < 1)
 | 
			
		||||
					throw new Exception ();
 | 
			
		||||
			} catch {
 | 
			
		||||
				context.ErrorMessage = "Invalid request line (version).";
 | 
			
		||||
				return;
 | 
			
		||||
				_context.ErrorMessage = "Invalid request line (version)";
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		internal static string Unquote (String str)
 | 
			
		||||
		{
 | 
			
		||||
			int start = str.IndexOf ('\"');
 | 
			
		||||
			int end = str.LastIndexOf ('\"');
 | 
			
		||||
			if (start >= 0 && end >=0)
 | 
			
		||||
				str = str.Substring (start + 1, end - 1);
 | 
			
		||||
			return str.Trim ();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		#endregion
 | 
			
		||||
 | 
			
		||||
		#region Public Methods
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user