Fix for request url

This commit is contained in:
sta 2014-05-28 14:20:46 +09:00
parent 9909c52d2d
commit 331d840775
8 changed files with 143 additions and 155 deletions

View File

@ -28,7 +28,6 @@
using System; using System;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Linq;
using System.Text; using System.Text;
using WebSocketSharp.Net; using WebSocketSharp.Net;
@ -38,10 +37,8 @@ namespace WebSocketSharp
{ {
#region Private Fields #region Private Fields
private string _method; private string _method;
private NameValueCollection _queryString; private string _uri;
private string _rawUrl;
private Uri _uri;
#endregion #endregion
@ -55,10 +52,9 @@ namespace WebSocketSharp
#region Public Constructors #region Public Constructors
public HandshakeRequest (string uriString) public HandshakeRequest (string absPathAndQuery)
{ {
_uri = uriString.ToUri (); _uri = absPathAndQuery;
_rawUrl = _uri.IsAbsoluteUri ? _uri.PathAndQuery : uriString;
_method = "GET"; _method = "GET";
var headers = Headers; var headers = Headers;
@ -73,9 +69,9 @@ namespace WebSocketSharp
public AuthenticationResponse AuthResponse { public AuthenticationResponse AuthResponse {
get { get {
var response = Headers ["Authorization"]; var auth = Headers ["Authorization"];
return response != null && response.Length > 0 return auth != null && auth.Length > 0
? AuthenticationResponse.Parse (response) ? AuthenticationResponse.Parse (auth)
: null; : null;
} }
} }
@ -100,47 +96,13 @@ namespace WebSocketSharp
get { get {
var headers = Headers; var headers = Headers;
return _method == "GET" && return _method == "GET" &&
ProtocolVersion >= HttpVersion.Version11 && ProtocolVersion > HttpVersion.Version10 &&
headers.Contains ("Upgrade", "websocket") && headers.Contains ("Upgrade", "websocket") &&
headers.Contains ("Connection", "Upgrade"); headers.Contains ("Connection", "Upgrade");
} }
} }
public NameValueCollection QueryString { public string RequestUri {
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 {
get { get {
return _uri; return _uri;
} }
@ -156,7 +118,7 @@ namespace WebSocketSharp
public static HandshakeRequest Parse (string [] headerParts) 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) if (requestLine.Length != 3)
throw new ArgumentException ("Invalid request line: " + headerParts [0]); throw new ArgumentException ("Invalid request line: " + headerParts [0]);
@ -168,8 +130,7 @@ namespace WebSocketSharp
Headers = headers, Headers = headers,
HttpMethod = requestLine [0], HttpMethod = requestLine [0],
ProtocolVersion = new Version (requestLine [2].Substring (5)), ProtocolVersion = new Version (requestLine [2].Substring (5)),
RawUrl = requestLine [1], RequestUri = requestLine [1]
RequestUri = requestLine [1].ToUri ()
}; };
} }
@ -178,32 +139,34 @@ namespace WebSocketSharp
if (cookies == null || cookies.Count == 0) if (cookies == null || cookies.Count == 0)
return; return;
var sorted = cookies.Sorted.ToArray (); var buff = new StringBuilder (64);
var header = new StringBuilder (sorted [0].ToString (), 64); foreach (var cookie in cookies.Sorted)
for (int i = 1; i < sorted.Length; i++) if (!cookie.Expired)
if (!sorted [i].Expired) buff.AppendFormat ("{0}; ", cookie.ToString ());
header.AppendFormat ("; {0}", sorted [i].ToString ());
Headers ["Cookie"] = header.ToString (); var len = buff.Length;
if (len > 2) {
buff.Length = len - 2;
Headers ["Cookie"] = buff.ToString ();
}
} }
public override string ToString () public override string ToString ()
{ {
var buffer = new StringBuilder (64); var buff = new StringBuilder (64);
buffer.AppendFormat ( buff.AppendFormat ("{0} {1} HTTP/{2}{3}", _method, _uri, ProtocolVersion, CrLf);
"{0} {1} HTTP/{2}{3}", _method, _rawUrl, ProtocolVersion, CrLf);
var headers = Headers; var headers = Headers;
foreach (var key in headers.AllKeys) 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; var entity = EntityBody;
if (entity.Length > 0) if (entity.Length > 0)
buffer.Append (entity); buff.Append (entity);
return buffer.ToString (); return buff.ToString ();
} }
#endregion #endregion

View File

@ -346,6 +346,7 @@ namespace WebSocketSharp.Net
/// </value> /// </value>
public string RawUrl { public string RawUrl {
get { get {
// TODO: Should decode?
return _url.PathAndQuery; return _url.PathAndQuery;
} }
} }
@ -467,7 +468,10 @@ namespace WebSocketSharp.Net
var i = component.IndexOf ('='); var i = component.IndexOf ('=');
if (i > -1) { if (i > -1) {
var name = HttpUtility.UrlDecode (component.Substring (0, i)); 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); res.Add (name, val);
} }
else { else {
@ -571,7 +575,7 @@ namespace WebSocketSharp.Net
string scheme = null; string scheme = null;
string path = null; string path = null;
if (_uri.StartsWith ("/")) { if (_uri.StartsWith ("/")) {
path = HttpUtility.UrlDecode (_uri); path = _uri;
} }
else if (_uri.MaybeUri ()) { else if (_uri.MaybeUri ()) {
Uri uri; Uri uri;
@ -589,7 +593,7 @@ namespace WebSocketSharp.Net
} }
else { else {
// As authority form // As authority form
host = HttpUtility.UrlDecode (_uri); host = _uri;
} }
if (scheme == null) if (scheme == null)

View File

@ -167,18 +167,6 @@ namespace WebSocketSharp.Net.WebSockets
} }
} }
/// <summary>
/// Gets the absolute path of the requested URI.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the absolute path of the requested URI.
/// </value>
public override string Path {
get {
return _context.Request.Url.GetAbsolutePath ();
}
}
/// <summary> /// <summary>
/// Gets the query string variables included in the request. /// Gets the query string variables included in the request.
/// </summary> /// </summary>

View File

@ -45,14 +45,15 @@ namespace WebSocketSharp.Net.WebSockets
{ {
#region Private Fields #region Private Fields
private TcpClient _client; private TcpClient _client;
private CookieCollection _cookies; private CookieCollection _cookies;
private HandshakeRequest _request; private NameValueCollection _queryString;
private bool _secure; private HandshakeRequest _request;
private WebSocketStream _stream; private bool _secure;
private Uri _uri; private WebSocketStream _stream;
private IPrincipal _user; private Uri _uri;
private WebSocket _websocket; private IPrincipal _user;
private WebSocket _websocket;
#endregion #endregion
@ -65,6 +66,7 @@ namespace WebSocketSharp.Net.WebSockets
_secure = secure; _secure = secure;
_stream = WebSocketStream.CreateServerStream (client, secure, cert); _stream = WebSocketStream.CreateServerStream (client, secure, cert);
_request = _stream.ReadHandshake<HandshakeRequest> (HandshakeRequest.Parse, 90000); _request = _stream.ReadHandshake<HandshakeRequest> (HandshakeRequest.Parse, 90000);
_uri = createRequestUrl (_request, secure);
_websocket = new WebSocket (this, protocol, logger); _websocket = new WebSocket (this, protocol, logger);
} }
@ -178,18 +180,6 @@ namespace WebSocketSharp.Net.WebSockets
} }
} }
/// <summary>
/// Gets the absolute path of the requested URI.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the absolute path of the requested URI.
/// </value>
public override string Path {
get {
return _request.RequestUri.GetAbsolutePath ();
}
}
/// <summary> /// <summary>
/// Gets the query string variables included in the request. /// Gets the query string variables included in the request.
/// </summary> /// </summary>
@ -198,7 +188,8 @@ namespace WebSocketSharp.Net.WebSockets
/// </value> /// </value>
public override NameValueCollection QueryString { public override NameValueCollection QueryString {
get { get {
return _request.QueryString; return _queryString ??
(_queryString = createQueryString (_uri != null ? _uri.Query : null));
} }
} }
@ -210,7 +201,7 @@ namespace WebSocketSharp.Net.WebSockets
/// </value> /// </value>
public override Uri RequestUri { public override Uri RequestUri {
get { get {
return _uri ?? (_uri = createRequestUri ()); return _uri;
} }
} }
@ -318,16 +309,78 @@ namespace WebSocketSharp.Net.WebSockets
#region Private Methods #region Private Methods
private Uri createRequestUri () private static NameValueCollection createQueryString (string query)
{ {
var scheme = _secure ? "wss" : "ws"; if (query == null || query.Length == 0)
var host = _request.Headers ["Host"]; return new NameValueCollection (1);
var rawUri = _request.RequestUri;
var path = rawUri.IsAbsoluteUri
? rawUri.PathAndQuery
: HttpUtility.UrlDecode (_request.RawUrl);
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 #endregion

View File

@ -118,14 +118,6 @@ namespace WebSocketSharp.Net.WebSockets
/// </value> /// </value>
public abstract string Origin { get; } public abstract string Origin { get; }
/// <summary>
/// Gets the absolute path of the requested URI.
/// </summary>
/// <value>
/// A <see cref="string"/> that represents the absolute path of the requested URI.
/// </value>
public abstract string Path { get; }
/// <summary> /// <summary>
/// Gets the query string variables included in the request. /// Gets the query string variables included in the request.
/// </summary> /// </summary>

View File

@ -505,10 +505,8 @@ namespace WebSocketSharp.Server
private void acceptWebSocketRequest (HttpListenerWebSocketContext context) private void acceptWebSocketRequest (HttpListenerWebSocketContext context)
{ {
var path = context.Path;
WebSocketServiceHost host; WebSocketServiceHost host;
if (path == null || !_services.TryGetServiceHostInternally (path, out host)) { if (!_services.TryGetServiceHostInternally (context.RequestUri.AbsolutePath, out host)) {
context.Close (HttpStatusCode.NotImplemented); context.Close (HttpStatusCode.NotImplemented);
return; return;
} }

View File

@ -492,16 +492,28 @@ namespace WebSocketSharp.Server
private void acceptWebSocket (TcpListenerWebSocketContext context) private void acceptWebSocket (TcpListenerWebSocketContext context)
{ {
var path = context.Path; var reqUri = context.RequestUri;
if (reqUri == null) {
WebSocketServiceHost host; context.Close (HttpStatusCode.BadRequest);
if (path == null || !_services.TryGetServiceHostInternally (path, out host)) {
context.Close (HttpStatusCode.NotImplemented);
return; return;
} }
if (_uri.IsAbsoluteUri) if (_uri.IsAbsoluteUri) {
context.WebSocket.Url = new Uri (_uri, path); 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); host.StartSession (context);
} }

View File

@ -118,7 +118,6 @@ namespace WebSocketSharp
_closeContext = context.Close; _closeContext = context.Close;
_secure = context.IsSecureConnection; _secure = context.IsSecureConnection;
_stream = context.Stream; _stream = context.Stream;
_uri = context.Path.ToUri ();
init (); init ();
} }
@ -133,7 +132,6 @@ namespace WebSocketSharp
_closeContext = context.Close; _closeContext = context.Close;
_secure = context.IsSecureConnection; _secure = context.IsSecureConnection;
_stream = context.Stream; _stream = context.Stream;
_uri = context.Path.ToUri ();
init (); init ();
} }
@ -459,11 +457,9 @@ namespace WebSocketSharp
/// </value> /// </value>
public Uri Url { public Uri Url {
get { get {
return _uri; return _client
} ? _uri
: _context.RequestUri;
internal set {
_uri = value;
} }
} }
@ -685,10 +681,10 @@ namespace WebSocketSharp
private string checkIfValidHandshakeRequest (WebSocketContext context) private string checkIfValidHandshakeRequest (WebSocketContext context)
{ {
var headers = context.Headers; var headers = context.Headers;
return !context.IsWebSocketRequest return context.RequestUri == null
? "Not WebSocket connection request." ? "Invalid request url."
: !validateHostHeader (headers ["Host"]) : !context.IsWebSocketRequest
? "Invalid Host header." ? "Not WebSocket connection request."
: !validateSecWebSocketKeyHeader (headers ["Sec-WebSocket-Key"]) : !validateSecWebSocketKeyHeader (headers ["Sec-WebSocket-Key"])
? "Invalid Sec-WebSocket-Key header." ? "Invalid Sec-WebSocket-Key header."
: !validateSecWebSocketVersionClientHeader (headers ["Sec-WebSocket-Version"]) : !validateSecWebSocketVersionClientHeader (headers ["Sec-WebSocket-Version"])
@ -1311,24 +1307,6 @@ namespace WebSocketSharp
receive (); 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 // As client
private bool validateSecWebSocketAcceptHeader (string value) private bool validateSecWebSocketAcceptHeader (string value)
{ {