diff --git a/websocket-sharp/Ext.cs b/websocket-sharp/Ext.cs
index 6ba24ece..c67192b8 100644
--- a/websocket-sharp/Ext.cs
+++ b/websocket-sharp/Ext.cs
@@ -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))
diff --git a/websocket-sharp/Net/HttpConnection.cs b/websocket-sharp/Net/HttpConnection.cs
index 5bde46cf..2ebf16a9 100644
--- a/websocket-sharp/Net/HttpConnection.cs
+++ b/websocket-sharp/Net/HttpConnection.cs
@@ -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 ("
{0} ({1})
", description, msg);
- else
- str = String.Format ("{0}
", description);
+ var description = status.GetStatusDescription ();
+ var error = !message.IsNullOrEmpty ()
+ ? String.Format ("{0} ({1})
", description, message)
+ : String.Format ("{0}
", 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.
}
}
diff --git a/websocket-sharp/Net/HttpListenerContext.cs b/websocket-sharp/Net/HttpListenerContext.cs
index 77e5cd09..d178db87 100644
--- a/websocket-sharp/Net/HttpListenerContext.cs
+++ b/websocket-sharp/Net/HttpListenerContext.cs
@@ -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 that contains the HTTP request objects.
///
public HttpListenerRequest Request {
- get { return request; }
+ get {
+ return _request;
+ }
}
///
@@ -116,7 +134,9 @@ namespace WebSocketSharp.Net {
/// A that contains the HTTP response objects.
///
public HttpListenerResponse Response {
- get { return response; }
+ get {
+ return _response;
+ }
}
///
@@ -126,7 +146,9 @@ namespace WebSocketSharp.Net {
/// A contains the client information.
///
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;
}
}
diff --git a/websocket-sharp/Net/HttpListenerRequest.cs b/websocket-sharp/Net/HttpListenerRequest.cs
index c9278e2f..50b6c2b8 100644
--- a/websocket-sharp/Net/HttpListenerRequest.cs
+++ b/websocket-sharp/Net/HttpListenerRequest.cs
@@ -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
///
/// Gets the media types which are acceptable for the response.
///
///
- /// An array of that contains the media type names in the Accept request-header field
+ /// An array of that contains the media type names in the Accept request-header
/// or if the request did not include an Accept header.
///
public string [] AcceptTypes {
- get { return accept_types; }
+ get {
+ return _acceptTypes;
+ }
}
///
@@ -110,12 +115,13 @@ namespace WebSocketSharp.Net {
/// Always returns 0.
///
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 {
}
///
- /// 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.
///
///
- /// A that contains the encoding that can be used with the entity body data.
+ /// A that indicates the encoding used with the entity body data
+ /// or if the request did not include the information about the encoding.
///
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.
///
///
- /// A that contains the value of the Content-Length entity-header field.
+ /// A that contains the value of the Content-Length entity-header.
/// The value is a number of bytes in the entity body data. -1 if the size is not known.
///
public long ContentLength64 {
- get { return content_length; }
+ get {
+ return _contentLength;
+ }
}
///
/// Gets the media type of the entity body included in the request.
///
///
- /// A that contains the value of the Content-Type entity-header field.
+ /// A that contains the value of the Content-Type entity-header.
///
public string ContentType {
- get { return headers ["content-type"]; }
+ get {
+ return _headers ["Content-Type"];
+ }
}
///
@@ -166,10 +177,10 @@ namespace WebSocketSharp.Net {
///
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 {
/// true if the request has the entity body; otherwise, false.
///
public bool HasEntityBody {
- get { return (content_length > 0 || is_chunked); }
+ get {
+ return _contentLength > 0 || _chunked;
+ }
}
///
@@ -190,7 +203,9 @@ namespace WebSocketSharp.Net {
/// A that contains the HTTP headers used in the request.
///
public NameValueCollection Headers {
- get { return headers; }
+ get {
+ return _headers;
+ }
}
///
@@ -200,7 +215,9 @@ namespace WebSocketSharp.Net {
/// A that contains the HTTP method used in the request.
///
public string HttpMethod {
- get { return method; }
+ get {
+ return _method;
+ }
}
///
@@ -211,14 +228,12 @@ namespace WebSocketSharp.Net {
///
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 false.
///
public bool IsAuthenticated {
- // TODO: Always returns false
- get { return false; }
+ get {
+ // TODO: Always returns false.
+ return false;
+ }
}
///
@@ -240,7 +257,9 @@ namespace WebSocketSharp.Net {
/// true if the request is sent from the local computer; otherwise, false.
///
public bool IsLocal {
- get { return RemoteEndPoint.Address.IsLocal(); }
+ get {
+ return RemoteEndPoint.Address.IsLocal ();
+ }
}
///
@@ -250,7 +269,9 @@ namespace WebSocketSharp.Net {
/// true if the HTTP connection is secured; otherwise, false.
///
public bool IsSecureConnection {
- get { return context.Connection.IsSecure; }
+ get {
+ return _context.Connection.IsSecure;
+ }
}
///
@@ -261,19 +282,19 @@ namespace WebSocketSharp.Net {
///
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 {
///
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 that contains the server endpoint.
///
public IPEndPoint LocalEndPoint {
- get { return context.Connection.LocalEndPoint; }
+ get {
+ return _context.Connection.LocalEndPoint;
+ }
}
///
@@ -323,7 +339,9 @@ namespace WebSocketSharp.Net {
/// A that contains the HTTP version used in the request.
///
public Version ProtocolVersion {
- get { return version; }
+ get {
+ return _version;
+ }
}
///
@@ -333,7 +351,9 @@ namespace WebSocketSharp.Net {
/// A that contains the collection of query string variables used in the request.
///
public NameValueCollection QueryString {
- get { return query_string; }
+ get {
+ return _queryString;
+ }
}
///
@@ -343,7 +363,9 @@ namespace WebSocketSharp.Net {
/// A that contains the raw URL requested by the client.
///
public string RawUrl {
- get { return raw_url; }
+ get {
+ return _rawUrl;
+ }
}
///
@@ -353,18 +375,21 @@ namespace WebSocketSharp.Net {
/// A that contains the client endpoint.
///
public IPEndPoint RemoteEndPoint {
- get { return context.Connection.RemoteEndPoint; }
+ get {
+ return _context.Connection.RemoteEndPoint;
+ }
}
///
- /// Gets the identifier of a request.
+ /// Gets the request identifier of a incoming HTTP request.
///
///
/// A that contains the identifier of a request.
///
public Guid RequestTraceIdentifier {
- // TODO: Always returns Guid.Empty
- get { return Guid.Empty; }
+ get {
+ return _identifier;
+ }
}
///
@@ -374,27 +399,34 @@ namespace WebSocketSharp.Net {
/// A that contains the URL requested by the client.
///
public Uri Url {
- get { return url; }
+ get {
+ return _url;
+ }
}
///
/// Gets the URL of the resource from which the requested URL was obtained.
///
///
- /// A that contains the value of the Referer request-header field.
+ /// A that contains the value of the Referer request-header
+ /// or if the request did not include an Referer header.
///
public Uri UrlReferrer {
- get { return referrer; }
+ get {
+ return _referer;
+ }
}
///
/// Gets the information about the user agent originating the request.
///
///
- /// A that contains the value of the User-Agent request-header field.
+ /// A that contains the value of the User-Agent request-header.
///
public string UserAgent {
- get { return headers ["user-agent"]; }
+ get {
+ return _headers ["User-Agent"];
+ }
}
///
@@ -404,52 +436,60 @@ namespace WebSocketSharp.Net {
/// A that contains the server endpoint.
///
public string UserHostAddress {
- get { return LocalEndPoint.ToString (); }
+ get {
+ return LocalEndPoint.ToString ();
+ }
}
///
- /// 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.
///
///
- /// A that contains the value of the Host request-header field.
+ /// A that contains the value of the Host request-header.
///
public string UserHostName {
- get { return headers ["host"]; }
+ get {
+ return _headers ["Host"];
+ }
}
///
- /// Gets the natural languages that are preferred as a response to the request.
+ /// Gets the natural languages which are preferred for the response.
///
///
- /// An array of that contains the natural language names in the Accept-Language request-header field.
+ /// An array of that contains the natural language names in the Accept-Language request-header
+ /// or if the request did not include an Accept-Language header.
///
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