diff --git a/websocket-sharp/HandshakeRequest.cs b/websocket-sharp/HandshakeRequest.cs index 92d90776..604ce6f6 100644 --- a/websocket-sharp/HandshakeRequest.cs +++ b/websocket-sharp/HandshakeRequest.cs @@ -28,7 +28,6 @@ using System; using System.Collections.Specialized; -using System.Linq; using System.Text; using WebSocketSharp.Net; @@ -38,10 +37,8 @@ namespace WebSocketSharp { #region Private Fields - private string _method; - private NameValueCollection _queryString; - private string _rawUrl; - private Uri _uri; + private string _method; + private string _uri; #endregion @@ -55,10 +52,9 @@ namespace WebSocketSharp #region Public Constructors - public HandshakeRequest (string uriString) + public HandshakeRequest (string absPathAndQuery) { - _uri = uriString.ToUri (); - _rawUrl = _uri.IsAbsoluteUri ? _uri.PathAndQuery : uriString; + _uri = absPathAndQuery; _method = "GET"; var headers = Headers; @@ -73,9 +69,9 @@ namespace WebSocketSharp public AuthenticationResponse AuthResponse { get { - var response = Headers ["Authorization"]; - return response != null && response.Length > 0 - ? AuthenticationResponse.Parse (response) + var auth = Headers ["Authorization"]; + return auth != null && auth.Length > 0 + ? AuthenticationResponse.Parse (auth) : null; } } @@ -100,47 +96,13 @@ namespace WebSocketSharp get { var headers = Headers; return _method == "GET" && - ProtocolVersion >= HttpVersion.Version11 && + ProtocolVersion > HttpVersion.Version10 && headers.Contains ("Upgrade", "websocket") && headers.Contains ("Connection", "Upgrade"); } } - public NameValueCollection QueryString { - get { - if (_queryString == null) { - _queryString = new NameValueCollection (); - - var i = RawUrl.IndexOf ('?'); - if (i > 0) { - var query = RawUrl.Substring (i + 1); - var components = query.Split ('&'); - foreach (var c in components) { - var nv = c.GetNameAndValue ("="); - if (nv.Key != null) { - var name = nv.Key.UrlDecode (); - var val = nv.Value.UrlDecode (); - _queryString.Add (name, val); - } - } - } - } - - return _queryString; - } - } - - public string RawUrl { - get { - return _rawUrl; - } - - private set { - _rawUrl = value; - } - } - - public Uri RequestUri { + public string RequestUri { get { return _uri; } @@ -156,7 +118,7 @@ namespace WebSocketSharp public static HandshakeRequest Parse (string [] headerParts) { - var requestLine = headerParts [0].Split (new char [] { ' ' }, 3); + var requestLine = headerParts [0].Split (new [] { ' ' }, 3); if (requestLine.Length != 3) throw new ArgumentException ("Invalid request line: " + headerParts [0]); @@ -168,8 +130,7 @@ namespace WebSocketSharp Headers = headers, HttpMethod = requestLine [0], ProtocolVersion = new Version (requestLine [2].Substring (5)), - RawUrl = requestLine [1], - RequestUri = requestLine [1].ToUri () + RequestUri = requestLine [1] }; } @@ -178,32 +139,34 @@ namespace WebSocketSharp if (cookies == null || cookies.Count == 0) return; - var sorted = cookies.Sorted.ToArray (); - var header = new StringBuilder (sorted [0].ToString (), 64); - for (int i = 1; i < sorted.Length; i++) - if (!sorted [i].Expired) - header.AppendFormat ("; {0}", sorted [i].ToString ()); + var buff = new StringBuilder (64); + foreach (var cookie in cookies.Sorted) + if (!cookie.Expired) + buff.AppendFormat ("{0}; ", cookie.ToString ()); - Headers ["Cookie"] = header.ToString (); + var len = buff.Length; + if (len > 2) { + buff.Length = len - 2; + Headers ["Cookie"] = buff.ToString (); + } } public override string ToString () { - var buffer = new StringBuilder (64); - buffer.AppendFormat ( - "{0} {1} HTTP/{2}{3}", _method, _rawUrl, ProtocolVersion, CrLf); + var buff = new StringBuilder (64); + buff.AppendFormat ("{0} {1} HTTP/{2}{3}", _method, _uri, ProtocolVersion, CrLf); var headers = Headers; foreach (var key in headers.AllKeys) - buffer.AppendFormat ("{0}: {1}{2}", key, headers [key], CrLf); + buff.AppendFormat ("{0}: {1}{2}", key, headers [key], CrLf); - buffer.Append (CrLf); + buff.Append (CrLf); var entity = EntityBody; if (entity.Length > 0) - buffer.Append (entity); + buff.Append (entity); - return buffer.ToString (); + return buff.ToString (); } #endregion diff --git a/websocket-sharp/Net/HttpListenerRequest.cs b/websocket-sharp/Net/HttpListenerRequest.cs index 1abaca02..6e6661b4 100644 --- a/websocket-sharp/Net/HttpListenerRequest.cs +++ b/websocket-sharp/Net/HttpListenerRequest.cs @@ -346,6 +346,7 @@ namespace WebSocketSharp.Net /// public string RawUrl { get { + // TODO: Should decode? return _url.PathAndQuery; } } @@ -467,7 +468,10 @@ namespace WebSocketSharp.Net var i = component.IndexOf ('='); if (i > -1) { var name = HttpUtility.UrlDecode (component.Substring (0, i)); - var val = HttpUtility.UrlDecode (component.Substring (i + 1)); + var val = component.Length > i + 1 + ? HttpUtility.UrlDecode (component.Substring (i + 1)) + : String.Empty; + res.Add (name, val); } else { @@ -571,7 +575,7 @@ namespace WebSocketSharp.Net string scheme = null; string path = null; if (_uri.StartsWith ("/")) { - path = HttpUtility.UrlDecode (_uri); + path = _uri; } else if (_uri.MaybeUri ()) { Uri uri; @@ -589,7 +593,7 @@ namespace WebSocketSharp.Net } else { // As authority form - host = HttpUtility.UrlDecode (_uri); + host = _uri; } if (scheme == null) diff --git a/websocket-sharp/Net/WebSockets/HttpListenerWebSocketContext.cs b/websocket-sharp/Net/WebSockets/HttpListenerWebSocketContext.cs index c47fd797..76892ccc 100644 --- a/websocket-sharp/Net/WebSockets/HttpListenerWebSocketContext.cs +++ b/websocket-sharp/Net/WebSockets/HttpListenerWebSocketContext.cs @@ -167,18 +167,6 @@ namespace WebSocketSharp.Net.WebSockets } } - /// - /// Gets the absolute path of the requested URI. - /// - /// - /// A that represents the absolute path of the requested URI. - /// - public override string Path { - get { - return _context.Request.Url.GetAbsolutePath (); - } - } - /// /// Gets the query string variables included in the request. /// diff --git a/websocket-sharp/Net/WebSockets/TcpListenerWebSocketContext.cs b/websocket-sharp/Net/WebSockets/TcpListenerWebSocketContext.cs index c9ec8338..48d428bd 100644 --- a/websocket-sharp/Net/WebSockets/TcpListenerWebSocketContext.cs +++ b/websocket-sharp/Net/WebSockets/TcpListenerWebSocketContext.cs @@ -45,14 +45,15 @@ namespace WebSocketSharp.Net.WebSockets { #region Private Fields - private TcpClient _client; - private CookieCollection _cookies; - private HandshakeRequest _request; - private bool _secure; - private WebSocketStream _stream; - private Uri _uri; - private IPrincipal _user; - private WebSocket _websocket; + private TcpClient _client; + private CookieCollection _cookies; + private NameValueCollection _queryString; + private HandshakeRequest _request; + private bool _secure; + private WebSocketStream _stream; + private Uri _uri; + private IPrincipal _user; + private WebSocket _websocket; #endregion @@ -65,6 +66,7 @@ namespace WebSocketSharp.Net.WebSockets _secure = secure; _stream = WebSocketStream.CreateServerStream (client, secure, cert); _request = _stream.ReadHandshake (HandshakeRequest.Parse, 90000); + _uri = createRequestUrl (_request, secure); _websocket = new WebSocket (this, protocol, logger); } @@ -178,18 +180,6 @@ namespace WebSocketSharp.Net.WebSockets } } - /// - /// Gets the absolute path of the requested URI. - /// - /// - /// A that represents the absolute path of the requested URI. - /// - public override string Path { - get { - return _request.RequestUri.GetAbsolutePath (); - } - } - /// /// Gets the query string variables included in the request. /// @@ -198,7 +188,8 @@ namespace WebSocketSharp.Net.WebSockets /// public override NameValueCollection QueryString { get { - return _request.QueryString; + return _queryString ?? + (_queryString = createQueryString (_uri != null ? _uri.Query : null)); } } @@ -210,7 +201,7 @@ namespace WebSocketSharp.Net.WebSockets /// public override Uri RequestUri { get { - return _uri ?? (_uri = createRequestUri ()); + return _uri; } } @@ -318,16 +309,78 @@ namespace WebSocketSharp.Net.WebSockets #region Private Methods - private Uri createRequestUri () + private static NameValueCollection createQueryString (string query) { - var scheme = _secure ? "wss" : "ws"; - var host = _request.Headers ["Host"]; - var rawUri = _request.RequestUri; - var path = rawUri.IsAbsoluteUri - ? rawUri.PathAndQuery - : HttpUtility.UrlDecode (_request.RawUrl); + if (query == null || query.Length == 0) + return new NameValueCollection (1); - return String.Format ("{0}://{1}{2}", scheme, host, path).ToUri (); + var res = new NameValueCollection (); + if (query [0] == '?') + query = query.Substring (1); + + var components = query.Split ('&'); + foreach (var component in components) { + var i = component.IndexOf ('='); + if (i > -1) { + var name = HttpUtility.UrlDecode (component.Substring (0, i)); + var val = component.Length > i + 1 + ? HttpUtility.UrlDecode (component.Substring (i + 1)) + : String.Empty; + + res.Add (name, val); + } + else { + res.Add (null, HttpUtility.UrlDecode (component)); + } + } + + return res; + } + + private static Uri createRequestUrl (HandshakeRequest request, bool secure) + { + var host = request.Headers ["Host"]; + if (host == null || host.Length == 0) + return null; + + string scheme = null; + string path = null; + + var reqUri = request.RequestUri; + if (reqUri.StartsWith ("/")) { + path = reqUri; + } + else if (reqUri.MaybeUri ()) { + Uri uri; + if (!Uri.TryCreate (reqUri, UriKind.Absolute, out uri) || + !uri.Scheme.StartsWith ("ws")) + return null; + + scheme = uri.Scheme; + host = uri.Authority; + path = uri.PathAndQuery; + } + else if (reqUri == "*") { + } + else { + // As authority form + host = reqUri; + } + + if (scheme == null) + scheme = secure ? "wss" : "ws"; + + var colon = host.IndexOf (':'); + if (colon == -1) + host = String.Format ("{0}:{1}", host, scheme == "ws" ? 80 : 443); + + var url = String.Format ("{0}://{1}{2}", scheme, host, path); + + Uri res; + if (!Uri.TryCreate (url, UriKind.Absolute, out res)) + return null; + + return res; } #endregion diff --git a/websocket-sharp/Net/WebSockets/WebSocketContext.cs b/websocket-sharp/Net/WebSockets/WebSocketContext.cs index 78930148..35803982 100644 --- a/websocket-sharp/Net/WebSockets/WebSocketContext.cs +++ b/websocket-sharp/Net/WebSockets/WebSocketContext.cs @@ -118,14 +118,6 @@ namespace WebSocketSharp.Net.WebSockets /// public abstract string Origin { get; } - /// - /// Gets the absolute path of the requested URI. - /// - /// - /// A that represents the absolute path of the requested URI. - /// - public abstract string Path { get; } - /// /// Gets the query string variables included in the request. /// diff --git a/websocket-sharp/Server/HttpServer.cs b/websocket-sharp/Server/HttpServer.cs index 19e14a6e..7b2d5491 100644 --- a/websocket-sharp/Server/HttpServer.cs +++ b/websocket-sharp/Server/HttpServer.cs @@ -505,10 +505,8 @@ namespace WebSocketSharp.Server private void acceptWebSocketRequest (HttpListenerWebSocketContext context) { - var path = context.Path; - WebSocketServiceHost host; - if (path == null || !_services.TryGetServiceHostInternally (path, out host)) { + if (!_services.TryGetServiceHostInternally (context.RequestUri.AbsolutePath, out host)) { context.Close (HttpStatusCode.NotImplemented); return; } diff --git a/websocket-sharp/Server/WebSocketServer.cs b/websocket-sharp/Server/WebSocketServer.cs index ce433bf9..712bf5fd 100644 --- a/websocket-sharp/Server/WebSocketServer.cs +++ b/websocket-sharp/Server/WebSocketServer.cs @@ -492,16 +492,28 @@ namespace WebSocketSharp.Server private void acceptWebSocket (TcpListenerWebSocketContext context) { - var path = context.Path; - - WebSocketServiceHost host; - if (path == null || !_services.TryGetServiceHostInternally (path, out host)) { - context.Close (HttpStatusCode.NotImplemented); + var reqUri = context.RequestUri; + if (reqUri == null) { + context.Close (HttpStatusCode.BadRequest); return; } - if (_uri.IsAbsoluteUri) - context.WebSocket.Url = new Uri (_uri, path); + if (_uri.IsAbsoluteUri) { + var req = reqUri.DnsSafeHost; + var expected = _uri.DnsSafeHost; + if (Uri.CheckHostName (req) == UriHostNameType.Dns && + Uri.CheckHostName (expected) == UriHostNameType.Dns && + req != expected) { + context.Close (HttpStatusCode.NotFound); + return; + } + } + + WebSocketServiceHost host; + if (!_services.TryGetServiceHostInternally (reqUri.AbsolutePath, out host)) { + context.Close (HttpStatusCode.NotImplemented); + return; + } host.StartSession (context); } diff --git a/websocket-sharp/WebSocket.cs b/websocket-sharp/WebSocket.cs index 8056dadc..5fc1e346 100644 --- a/websocket-sharp/WebSocket.cs +++ b/websocket-sharp/WebSocket.cs @@ -118,7 +118,6 @@ namespace WebSocketSharp _closeContext = context.Close; _secure = context.IsSecureConnection; _stream = context.Stream; - _uri = context.Path.ToUri (); init (); } @@ -133,7 +132,6 @@ namespace WebSocketSharp _closeContext = context.Close; _secure = context.IsSecureConnection; _stream = context.Stream; - _uri = context.Path.ToUri (); init (); } @@ -459,11 +457,9 @@ namespace WebSocketSharp /// public Uri Url { get { - return _uri; - } - - internal set { - _uri = value; + return _client + ? _uri + : _context.RequestUri; } } @@ -685,10 +681,10 @@ namespace WebSocketSharp private string checkIfValidHandshakeRequest (WebSocketContext context) { var headers = context.Headers; - return !context.IsWebSocketRequest - ? "Not WebSocket connection request." - : !validateHostHeader (headers ["Host"]) - ? "Invalid Host header." + return context.RequestUri == null + ? "Invalid request url." + : !context.IsWebSocketRequest + ? "Not WebSocket connection request." : !validateSecWebSocketKeyHeader (headers ["Sec-WebSocket-Key"]) ? "Invalid Sec-WebSocket-Key header." : !validateSecWebSocketVersionClientHeader (headers ["Sec-WebSocket-Version"]) @@ -1311,24 +1307,6 @@ namespace WebSocketSharp receive (); } - // As server - private bool validateHostHeader (string value) - { - if (value == null || value.Length == 0) - return false; - - if (!_uri.IsAbsoluteUri) - return true; - - var i = value.IndexOf (':'); - var host = i > 0 ? value.Substring (0, i) : value; - var expected = _uri.DnsSafeHost; - - return Uri.CheckHostName (host) != UriHostNameType.Dns || - Uri.CheckHostName (expected) != UriHostNameType.Dns || - host == expected; - } - // As client private bool validateSecWebSocketAcceptHeader (string value) {