Modified opening and closing handshake
This commit is contained in:
parent
7deddda2f9
commit
69c9be3eb5
@ -56,7 +56,7 @@ namespace WebSocketSharp
|
||||
{
|
||||
_code = getCodeFrom (data);
|
||||
_reason = getReasonFrom (data);
|
||||
_clean = true;
|
||||
_clean = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -225,6 +225,11 @@ namespace WebSocketSharp {
|
||||
: stream.ToByteArray();
|
||||
}
|
||||
|
||||
internal static bool Equals (this string value, CompressionMethod method)
|
||||
{
|
||||
return value == method.ToCompressionExtension ();
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Determines whether the specified <see cref="int"/> equals the specified <see cref="char"/>,
|
||||
// and invokes the specified Action<int> delegate at the same time.
|
||||
@ -289,6 +294,11 @@ namespace WebSocketSharp {
|
||||
return new TcpListenerWebSocketContext(client, secure, cert);
|
||||
}
|
||||
|
||||
internal static bool IsCompressionExtension (this string value)
|
||||
{
|
||||
return value.StartsWith ("permessage-");
|
||||
}
|
||||
|
||||
// <summary>
|
||||
// Determines whether the specified object is <see langword="null"/>.
|
||||
// </summary>
|
||||
@ -514,6 +524,22 @@ namespace WebSocketSharp {
|
||||
}
|
||||
}
|
||||
|
||||
internal static string ToCompressionExtension (this CompressionMethod method)
|
||||
{
|
||||
return method != CompressionMethod.NONE
|
||||
? String.Format ("permessage-{0}", method.ToString ().ToLower ())
|
||||
: String.Empty;
|
||||
}
|
||||
|
||||
internal static CompressionMethod ToCompressionMethod (this string value)
|
||||
{
|
||||
foreach (CompressionMethod method in Enum.GetValues (typeof (CompressionMethod)))
|
||||
if (value.Equals (method))
|
||||
return method;
|
||||
|
||||
return CompressionMethod.NONE;
|
||||
}
|
||||
|
||||
internal static string Unquote(this string value)
|
||||
{
|
||||
var start = value.IndexOf('\"');
|
||||
|
@ -78,19 +78,10 @@ namespace WebSocketSharp
|
||||
|
||||
public bool IsWebSocketRequest {
|
||||
get {
|
||||
return HttpMethod != "GET"
|
||||
? false
|
||||
: ProtocolVersion < HttpVersion.Version11
|
||||
? false
|
||||
: !ContainsHeader ("Upgrade", "websocket")
|
||||
? false
|
||||
: !ContainsHeader ("Connection", "Upgrade")
|
||||
? false
|
||||
: !ContainsHeader ("Host")
|
||||
? false
|
||||
: !ContainsHeader ("Sec-WebSocket-Key")
|
||||
? false
|
||||
: ContainsHeader ("Sec-WebSocket-Version");
|
||||
return HttpMethod == "GET" &&
|
||||
ProtocolVersion >= HttpVersion.Version11 &&
|
||||
Headers.Contains ("Upgrade", "websocket") &&
|
||||
Headers.Contains ("Connection", "Upgrade");
|
||||
}
|
||||
}
|
||||
|
||||
@ -158,16 +149,6 @@ namespace WebSocketSharp
|
||||
};
|
||||
}
|
||||
|
||||
public static HandshakeRequest Parse (WebSocketContext context)
|
||||
{
|
||||
return new HandshakeRequest {
|
||||
Headers = context.Headers,
|
||||
HttpMethod = "GET",
|
||||
RequestUri = context.RequestUri,
|
||||
ProtocolVersion = HttpVersion.Version11
|
||||
};
|
||||
}
|
||||
|
||||
public void SetCookies (CookieCollection cookies)
|
||||
{
|
||||
if (cookies == null || cookies.Count == 0)
|
||||
|
@ -57,8 +57,9 @@ namespace WebSocketSharp
|
||||
|
||||
public AuthenticationChallenge AuthChallenge {
|
||||
get {
|
||||
return ContainsHeader ("WWW-Authenticate")
|
||||
? AuthenticationChallenge.Parse (Headers ["WWW-Authenticate"])
|
||||
var challenge = Headers ["WWW-Authenticate"];
|
||||
return !challenge.IsNullOrEmpty ()
|
||||
? AuthenticationChallenge.Parse (challenge)
|
||||
: null;
|
||||
}
|
||||
}
|
||||
@ -77,15 +78,11 @@ namespace WebSocketSharp
|
||||
|
||||
public bool IsWebSocketResponse {
|
||||
get {
|
||||
return ProtocolVersion < HttpVersion.Version11
|
||||
? false
|
||||
: StatusCode != "101"
|
||||
? false
|
||||
: !ContainsHeader ("Upgrade", "websocket")
|
||||
? false
|
||||
: !ContainsHeader ("Connection", "Upgrade")
|
||||
? false
|
||||
: ContainsHeader ("Sec-WebSocket-Accept");
|
||||
return ProtocolVersion >= HttpVersion.Version11 &&
|
||||
StatusCode == "101" &&
|
||||
Headers.Contains ("Upgrade", "websocket") &&
|
||||
Headers.Contains ("Connection", "Upgrade") &&
|
||||
!Headers ["Sec-WebSocket-Accept"].IsNullOrEmpty ();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
// Gonzalo Paniagua Javier (gonzalo@novell.com)
|
||||
//
|
||||
// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
|
||||
// Copyright (c) 2012-2013 sta.blockhead (sta.blockhead@gmail.com)
|
||||
// Copyright (c) 2012-2013 sta.blockhead
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
@ -40,16 +40,16 @@ using System.Net;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
|
||||
namespace WebSocketSharp.Net {
|
||||
|
||||
namespace WebSocketSharp.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides access to a request to a <see cref="HttpListener"/> instance.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The HttpListenerRequest class cannot be inherited.
|
||||
/// </remarks>
|
||||
public sealed class HttpListenerRequest {
|
||||
|
||||
public sealed class HttpListenerRequest
|
||||
{
|
||||
#region Private Static Fields
|
||||
|
||||
private static byte [] _100continue = Encoding.ASCII.GetBytes ("HTTP/1.1 100 Continue\r\n\r\n");
|
||||
@ -282,19 +282,10 @@ namespace WebSocketSharp.Net {
|
||||
/// </value>
|
||||
public bool IsWebSocketRequest {
|
||||
get {
|
||||
return _method != "GET"
|
||||
? false
|
||||
: _version < HttpVersion.Version11
|
||||
? false
|
||||
: !_headers.Contains("Upgrade", "websocket")
|
||||
? false
|
||||
: !_headers.Contains("Connection", "Upgrade")
|
||||
? false
|
||||
: !_headers.Contains("Host")
|
||||
? false
|
||||
: !_headers.Contains("Sec-WebSocket-Key")
|
||||
? false
|
||||
: _headers.Contains("Sec-WebSocket-Version");
|
||||
return _method == "GET" &&
|
||||
_version >= HttpVersion.Version11 &&
|
||||
_headers.Contains ("Upgrade", "websocket") &&
|
||||
_headers.Contains ("Connection", "Upgrade");
|
||||
}
|
||||
}
|
||||
|
||||
@ -744,6 +735,23 @@ namespace WebSocketSharp.Net {
|
||||
throw new NotImplementedException ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="string"/> that represents the current <see cref="HttpListenerRequest"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="string"/> that represents the current <see cref="HttpListenerRequest"/>.
|
||||
/// </returns>
|
||||
public override string ToString ()
|
||||
{
|
||||
var buffer = new StringBuilder (64);
|
||||
buffer.AppendFormat ("{0} {1} HTTP/{2}\r\n", _method, _rawUrl, _version);
|
||||
foreach (string key in _headers.AllKeys)
|
||||
buffer.AppendFormat ("{0}: {1}\r\n", key, _headers [key]);
|
||||
|
||||
buffer.Append ("\r\n");
|
||||
return buffer.ToString ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -31,10 +31,10 @@ using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Security.Principal;
|
||||
|
||||
namespace WebSocketSharp.Net.WebSockets {
|
||||
|
||||
namespace WebSocketSharp.Net.WebSockets
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides access to the WebSocket connection request objects received by the <see cref="HttpListener"/> class.
|
||||
/// Provides access to the WebSocket connection request objects received by the <see cref="HttpListener"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
@ -44,7 +44,7 @@ namespace WebSocketSharp.Net.WebSockets {
|
||||
|
||||
private HttpListenerContext _context;
|
||||
private WebSocket _websocket;
|
||||
private WsStream _wsStream;
|
||||
private WsStream _stream;
|
||||
|
||||
#endregion
|
||||
|
||||
@ -53,7 +53,7 @@ namespace WebSocketSharp.Net.WebSockets {
|
||||
internal HttpListenerWebSocketContext (HttpListenerContext context)
|
||||
{
|
||||
_context = context;
|
||||
_wsStream = WsStream.CreateServerStream(context);
|
||||
_stream = WsStream.CreateServerStream (context);
|
||||
_websocket = new WebSocket (this);
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ namespace WebSocketSharp.Net.WebSockets {
|
||||
|
||||
internal WsStream Stream {
|
||||
get {
|
||||
return _wsStream;
|
||||
return _stream;
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,6 +95,18 @@ namespace WebSocketSharp.Net.WebSockets {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the Host header field used in the WebSocket opening handshake.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string"/> that contains the value of the Host header field.
|
||||
/// </value>
|
||||
public override string Host {
|
||||
get {
|
||||
return _context.Request.Headers ["Host"];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the client is authenticated.
|
||||
/// </summary>
|
||||
@ -132,18 +144,14 @@ namespace WebSocketSharp.Net.WebSockets {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the WebSocket connection request is valid.
|
||||
/// Gets a value indicating whether the request is a WebSocket connection request.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if the WebSocket connection request is valid; otherwise, <c>false</c>.
|
||||
/// <c>true</c> if the request is a WebSocket connection request; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public override bool IsValid {
|
||||
public override bool IsWebSocketRequest {
|
||||
get {
|
||||
return !_context.Request.IsWebSocketRequest
|
||||
? false
|
||||
: SecWebSocketKey.IsNullOrEmpty()
|
||||
? false
|
||||
: !SecWebSocketVersion.IsNullOrEmpty();
|
||||
return _context.Request.IsWebSocketRequest;
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,7 +163,7 @@ namespace WebSocketSharp.Net.WebSockets {
|
||||
/// </value>
|
||||
public override string Origin {
|
||||
get {
|
||||
return Headers["Origin"];
|
||||
return _context.Request.Headers ["Origin"];
|
||||
}
|
||||
}
|
||||
|
||||
@ -206,7 +214,7 @@ namespace WebSocketSharp.Net.WebSockets {
|
||||
/// </value>
|
||||
public override string SecWebSocketKey {
|
||||
get {
|
||||
return Headers["Sec-WebSocket-Key"];
|
||||
return _context.Request.Headers ["Sec-WebSocket-Key"];
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,7 +229,7 @@ namespace WebSocketSharp.Net.WebSockets {
|
||||
/// </value>
|
||||
public override IEnumerable<string> SecWebSocketProtocols {
|
||||
get {
|
||||
return Headers.GetValues("Sec-WebSocket-Protocol");
|
||||
return _context.Request.Headers.GetValues ("Sec-WebSocket-Protocol");
|
||||
}
|
||||
}
|
||||
|
||||
@ -236,7 +244,7 @@ namespace WebSocketSharp.Net.WebSockets {
|
||||
/// </value>
|
||||
public override string SecWebSocketVersion {
|
||||
get {
|
||||
return Headers["Sec-WebSocket-Version"];
|
||||
return _context.Request.Headers ["Sec-WebSocket-Version"];
|
||||
}
|
||||
}
|
||||
|
||||
@ -246,7 +254,7 @@ namespace WebSocketSharp.Net.WebSockets {
|
||||
/// <value>
|
||||
/// A <see cref="System.Net.IPEndPoint"/> that contains the server endpoint.
|
||||
/// </value>
|
||||
public virtual System.Net.IPEndPoint ServerEndPoint {
|
||||
public override System.Net.IPEndPoint ServerEndPoint {
|
||||
get {
|
||||
return _context.Connection.LocalEndPoint;
|
||||
}
|
||||
@ -270,7 +278,7 @@ namespace WebSocketSharp.Net.WebSockets {
|
||||
/// <value>
|
||||
/// A <see cref="System.Net.IPEndPoint"/> that contains the client endpoint.
|
||||
/// </value>
|
||||
public virtual System.Net.IPEndPoint UserEndPoint {
|
||||
public override System.Net.IPEndPoint UserEndPoint {
|
||||
get {
|
||||
return _context.Connection.RemoteEndPoint;
|
||||
}
|
||||
@ -298,5 +306,20 @@ namespace WebSocketSharp.Net.WebSockets {
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="string"/> that represents the current <see cref="HttpListenerWebSocketContext"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="string"/> that represents the current <see cref="HttpListenerWebSocketContext"/>.
|
||||
/// </returns>
|
||||
public override string ToString ()
|
||||
{
|
||||
return _context.Request.ToString ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -105,6 +105,18 @@ namespace WebSocketSharp.Net.WebSockets
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the Host header field used in the WebSocket opening handshake.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string"/> that contains the value of the Host header field.
|
||||
/// </value>
|
||||
public override string Host {
|
||||
get {
|
||||
return _request.Headers ["Host"];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the client is authenticated.
|
||||
/// </summary>
|
||||
@ -145,18 +157,14 @@ namespace WebSocketSharp.Net.WebSockets
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the WebSocket connection request is valid.
|
||||
/// Gets a value indicating whether the request is a WebSocket connection request.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if the WebSocket connection request is valid; otherwise, <c>false</c>.
|
||||
/// <c>true</c> if the request is a WebSocket connection request; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public override bool IsValid {
|
||||
public override bool IsWebSocketRequest {
|
||||
get {
|
||||
return !_request.IsWebSocketRequest
|
||||
? false
|
||||
: SecWebSocketKey.IsNullOrEmpty ()
|
||||
? false
|
||||
: !SecWebSocketVersion.IsNullOrEmpty ();
|
||||
return _request.IsWebSocketRequest;
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,7 +176,7 @@ namespace WebSocketSharp.Net.WebSockets
|
||||
/// </value>
|
||||
public override string Origin {
|
||||
get {
|
||||
return Headers ["Origin"];
|
||||
return _request.Headers ["Origin"];
|
||||
}
|
||||
}
|
||||
|
||||
@ -219,7 +227,7 @@ namespace WebSocketSharp.Net.WebSockets
|
||||
/// </value>
|
||||
public override string SecWebSocketKey {
|
||||
get {
|
||||
return Headers ["Sec-WebSocket-Key"];
|
||||
return _request.Headers ["Sec-WebSocket-Key"];
|
||||
}
|
||||
}
|
||||
|
||||
@ -227,14 +235,14 @@ namespace WebSocketSharp.Net.WebSockets
|
||||
/// Gets the values of the Sec-WebSocket-Protocol header field used in the WebSocket opening handshake.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The SecWebSocketProtocols property indicates the subprotocols of the WebSocket connection.
|
||||
/// This property indicates the subprotocols of the WebSocket connection.
|
||||
/// </remarks>
|
||||
/// <value>
|
||||
/// An IEnumerable<string> that contains the values of the Sec-WebSocket-Protocol header field.
|
||||
/// </value>
|
||||
public override IEnumerable<string> SecWebSocketProtocols {
|
||||
get {
|
||||
return Headers.GetValues ("Sec-WebSocket-Protocol");
|
||||
return _request.Headers.GetValues ("Sec-WebSocket-Protocol");
|
||||
}
|
||||
}
|
||||
|
||||
@ -249,7 +257,7 @@ namespace WebSocketSharp.Net.WebSockets
|
||||
/// </value>
|
||||
public override string SecWebSocketVersion {
|
||||
get {
|
||||
return Headers ["Sec-WebSocket-Version"];
|
||||
return _request.Headers ["Sec-WebSocket-Version"];
|
||||
}
|
||||
}
|
||||
|
||||
@ -259,7 +267,7 @@ namespace WebSocketSharp.Net.WebSockets
|
||||
/// <value>
|
||||
/// A <see cref="System.Net.IPEndPoint"/> that contains the server endpoint.
|
||||
/// </value>
|
||||
public virtual System.Net.IPEndPoint ServerEndPoint {
|
||||
public override System.Net.IPEndPoint ServerEndPoint {
|
||||
get {
|
||||
return (System.Net.IPEndPoint) _client.Client.LocalEndPoint;
|
||||
}
|
||||
@ -286,7 +294,7 @@ namespace WebSocketSharp.Net.WebSockets
|
||||
/// <value>
|
||||
/// A <see cref="System.Net.IPEndPoint"/> that contains the client endpoint.
|
||||
/// </value>
|
||||
public virtual System.Net.IPEndPoint UserEndPoint {
|
||||
public override System.Net.IPEndPoint UserEndPoint {
|
||||
get {
|
||||
return (System.Net.IPEndPoint) _client.Client.RemoteEndPoint;
|
||||
}
|
||||
@ -315,5 +323,20 @@ namespace WebSocketSharp.Net.WebSockets
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="string"/> that represents the current <see cref="TcpListenerWebSocketContext"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="string"/> that represents the current <see cref="TcpListenerWebSocketContext"/>.
|
||||
/// </returns>
|
||||
public override string ToString ()
|
||||
{
|
||||
return _request.ToString ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -31,16 +31,16 @@ using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Security.Principal;
|
||||
|
||||
namespace WebSocketSharp.Net.WebSockets {
|
||||
|
||||
namespace WebSocketSharp.Net.WebSockets
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides access to the WebSocket connection request objects.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The WebSocketContext class is an abstract class.
|
||||
/// </remarks>
|
||||
public abstract class WebSocketContext {
|
||||
|
||||
public abstract class WebSocketContext
|
||||
{
|
||||
#region Protected Constructors
|
||||
|
||||
/// <summary>
|
||||
@ -70,6 +70,14 @@ namespace WebSocketSharp.Net.WebSockets {
|
||||
/// </value>
|
||||
public abstract NameValueCollection Headers { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the Host header field used in the WebSocket opening handshake.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="string"/> that contains the value of the Host header field.
|
||||
/// </value>
|
||||
public abstract string Host { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the client is authenticated.
|
||||
/// </summary>
|
||||
@ -95,12 +103,12 @@ namespace WebSocketSharp.Net.WebSockets {
|
||||
public abstract bool IsSecureConnection { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the WebSocket connection request is valid.
|
||||
/// Gets a value indicating whether the request is a WebSocket connection request.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if the WebSocket connection request is valid; otherwise, <c>false</c>.
|
||||
/// <c>true</c> if the request is a WebSocket connection request; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public abstract bool IsValid { get; }
|
||||
public abstract bool IsWebSocketRequest { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the Origin header field used in the WebSocket opening handshake.
|
||||
@ -167,6 +175,14 @@ namespace WebSocketSharp.Net.WebSockets {
|
||||
/// </value>
|
||||
public abstract string SecWebSocketVersion { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the server endpoint as an IP address and a port number.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="System.Net.IPEndPoint"/> that contains the server endpoint.
|
||||
/// </value>
|
||||
public abstract System.Net.IPEndPoint ServerEndPoint { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the client information (identity, authentication information and security roles).
|
||||
/// </summary>
|
||||
@ -175,6 +191,14 @@ namespace WebSocketSharp.Net.WebSockets {
|
||||
/// </value>
|
||||
public abstract IPrincipal User { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the client endpoint as an IP address and a port number.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// A <see cref="System.Net.IPEndPoint"/> that contains the client endpoint.
|
||||
/// </value>
|
||||
public abstract System.Net.IPEndPoint UserEndPoint { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the WebSocket instance used for two-way communication between client and server.
|
||||
/// </summary>
|
||||
|
@ -45,8 +45,8 @@ using System.Threading;
|
||||
using WebSocketSharp.Net;
|
||||
using WebSocketSharp.Net.WebSockets;
|
||||
|
||||
namespace WebSocketSharp {
|
||||
|
||||
namespace WebSocketSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements the WebSocket interface.
|
||||
/// </summary>
|
||||
@ -499,9 +499,29 @@ namespace WebSocketSharp {
|
||||
// As server
|
||||
private bool acceptHandshake ()
|
||||
{
|
||||
return processHandshakeRequest ()
|
||||
? send (createHandshakeResponse ())
|
||||
: false;
|
||||
_logger.Debug (String.Format ("A WebSocket connection request from {0}:\n{1}",
|
||||
_context.UserEndPoint, _context));
|
||||
|
||||
if (!validateConnectionRequest (_context))
|
||||
{
|
||||
var msg = "Invalid WebSocket connection request.";
|
||||
_logger.Error (msg);
|
||||
error (msg);
|
||||
Close (HttpStatusCode.BadRequest);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
_base64key = _context.SecWebSocketKey;
|
||||
|
||||
if (_protocol.Length > 0 && !_context.Headers.Contains ("Sec-WebSocket-Protocol", _protocol))
|
||||
_protocol = String.Empty;
|
||||
|
||||
var extensions = _context.Headers ["Sec-WebSocket-Extensions"];
|
||||
if (extensions != null && extensions.Length > 0)
|
||||
processRequestedExtensions (extensions);
|
||||
|
||||
return send (createHandshakeResponse ());
|
||||
}
|
||||
|
||||
private void close (CloseEventArgs eventArgs)
|
||||
@ -532,7 +552,10 @@ namespace WebSocketSharp {
|
||||
if (state == WsState.CONNECTING)
|
||||
{
|
||||
if (!_client)
|
||||
args.WasClean = send (createHandshakeResponse (HttpStatusCode.BadRequest));
|
||||
{
|
||||
close (HttpStatusCode.BadRequest);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -545,6 +568,14 @@ namespace WebSocketSharp {
|
||||
_logger.Trace ("Exit close method.");
|
||||
}
|
||||
|
||||
// As server
|
||||
private void close (HttpStatusCode code)
|
||||
{
|
||||
send (createHandshakeResponse (code));
|
||||
closeResources ();
|
||||
_readyState = WsState.CLOSED;
|
||||
}
|
||||
|
||||
private void close (ushort code, string reason)
|
||||
{
|
||||
var data = code.Append (reason);
|
||||
@ -672,11 +703,6 @@ namespace WebSocketSharp {
|
||||
return Convert.ToBase64String (src);
|
||||
}
|
||||
|
||||
private static string createCompressionExtension(CompressionMethod method)
|
||||
{
|
||||
return createCurrentCompressionExtension(method);
|
||||
}
|
||||
|
||||
private static WsFrame createControlFrame (Opcode opcode, PayloadData payloadData, bool client)
|
||||
{
|
||||
var mask = client ? Mask.MASK : Mask.UNMASK;
|
||||
@ -685,20 +711,6 @@ namespace WebSocketSharp {
|
||||
return frame;
|
||||
}
|
||||
|
||||
private static string createCurrentCompressionExtension(CompressionMethod method)
|
||||
{
|
||||
return method != CompressionMethod.NONE
|
||||
? String.Format("permessage-{0}", method.ToString().ToLower())
|
||||
: String.Empty;
|
||||
}
|
||||
|
||||
private static string createDeprecatedCompressionExtension(CompressionMethod method)
|
||||
{
|
||||
return method != CompressionMethod.NONE
|
||||
? String.Format("permessage-compress; method={0}", method.ToString().ToLower())
|
||||
: String.Empty;
|
||||
}
|
||||
|
||||
private static WsFrame createFrame (
|
||||
Fin fin, Opcode opcode, PayloadData payloadData, bool compressed, bool client)
|
||||
{
|
||||
@ -747,6 +759,10 @@ namespace WebSocketSharp {
|
||||
{
|
||||
var res = new HandshakeResponse ();
|
||||
res.AddHeader ("Sec-WebSocket-Accept", createResponseKey ());
|
||||
|
||||
if (_protocol.Length > 0)
|
||||
res.AddHeader ("Sec-WebSocket-Protocol", _protocol);
|
||||
|
||||
if (_extensions.Length > 0)
|
||||
res.AddHeader ("Sec-WebSocket-Extensions", _extensions);
|
||||
|
||||
@ -769,9 +785,8 @@ namespace WebSocketSharp {
|
||||
private string createRequestExtensions ()
|
||||
{
|
||||
var extensions = new StringBuilder (64);
|
||||
var comp = createCompressionExtension (_compression);
|
||||
if (comp.Length > 0)
|
||||
extensions.Append (comp);
|
||||
if (_compression != CompressionMethod.NONE)
|
||||
extensions.Append (_compression.ToCompressionExtension ());
|
||||
|
||||
return extensions.Length > 0
|
||||
? extensions.ToString ()
|
||||
@ -792,7 +807,33 @@ namespace WebSocketSharp {
|
||||
private bool doHandshake ()
|
||||
{
|
||||
setClientStream ();
|
||||
return processHandshakeResponse (sendHandshakeRequest ());
|
||||
var res = sendHandshakeRequest ();
|
||||
var msg = res.IsUnauthorized
|
||||
? String.Format ("An HTTP {0} authorization is required.", res.AuthChallenge.Scheme)
|
||||
: !validateConnectionResponse (res)
|
||||
? "Invalid response to this WebSocket connection request."
|
||||
: String.Empty;
|
||||
|
||||
if (msg.Length > 0)
|
||||
{
|
||||
_logger.Error (msg);
|
||||
error (msg);
|
||||
Close (CloseStatusCode.ABNORMAL, msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
var protocol = res.Headers ["Sec-WebSocket-Protocol"];
|
||||
if (protocol != null && protocol.Length > 0)
|
||||
_protocol = protocol;
|
||||
|
||||
processRespondedExtensions (res.Headers ["Sec-WebSocket-Extensions"]);
|
||||
|
||||
var cookies = res.Cookies;
|
||||
if (cookies.Count > 0)
|
||||
_cookies.SetOrRemove (cookies);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void error (string message)
|
||||
@ -800,19 +841,6 @@ namespace WebSocketSharp {
|
||||
OnError.Emit (this, new ErrorEventArgs (message));
|
||||
}
|
||||
|
||||
private static CompressionMethod getCompressionMethod(string value)
|
||||
{
|
||||
var deprecated = createDeprecatedCompressionExtension(CompressionMethod.DEFLATE);
|
||||
if (value.Equals(deprecated))
|
||||
return CompressionMethod.DEFLATE;
|
||||
|
||||
foreach (CompressionMethod method in Enum.GetValues(typeof(CompressionMethod)))
|
||||
if (isCompressionExtension(value, method))
|
||||
return method;
|
||||
|
||||
return CompressionMethod.NONE;
|
||||
}
|
||||
|
||||
// As server
|
||||
private void init (WebSocketContext context)
|
||||
{
|
||||
@ -822,60 +850,6 @@ namespace WebSocketSharp {
|
||||
_client = false;
|
||||
}
|
||||
|
||||
private static bool isCompressionExtension(string value)
|
||||
{
|
||||
return value.StartsWith("permessage-");
|
||||
}
|
||||
|
||||
private static bool isCompressionExtension(string value, CompressionMethod method)
|
||||
{
|
||||
var expected = createCompressionExtension(method);
|
||||
return expected.Length > 0
|
||||
? value.Equals(expected)
|
||||
: false;
|
||||
}
|
||||
|
||||
// As server
|
||||
private bool isValidHostHeader()
|
||||
{
|
||||
var authority = _context.Headers["Host"];
|
||||
if (authority.IsNullOrEmpty() || !_uri.IsAbsoluteUri)
|
||||
return true;
|
||||
|
||||
var i = authority.IndexOf(':');
|
||||
var host = i > 0
|
||||
? authority.Substring(0, i)
|
||||
: authority;
|
||||
var type = Uri.CheckHostName(host);
|
||||
|
||||
return type != UriHostNameType.Dns
|
||||
? true
|
||||
: Uri.CheckHostName(_uri.DnsSafeHost) != UriHostNameType.Dns
|
||||
? true
|
||||
: host == _uri.DnsSafeHost;
|
||||
}
|
||||
|
||||
// As server
|
||||
private bool isValidRequesHandshake()
|
||||
{
|
||||
return !_context.IsValid
|
||||
? false
|
||||
: !isValidHostHeader()
|
||||
? false
|
||||
: _context.Headers.Contains("Sec-WebSocket-Version", _version);
|
||||
}
|
||||
|
||||
// As client
|
||||
private bool isValidHandshakeResponse (HandshakeResponse response)
|
||||
{
|
||||
return !response.IsWebSocketResponse
|
||||
? false
|
||||
: !response.ContainsHeader ("Sec-WebSocket-Accept", createResponseKey ())
|
||||
? false
|
||||
: !response.ContainsHeader ("Sec-WebSocket-Version") ||
|
||||
response.ContainsHeader ("Sec-WebSocket-Version", _version);
|
||||
}
|
||||
|
||||
private void open ()
|
||||
{
|
||||
_readyState = WsState.OPEN;
|
||||
@ -1025,25 +999,22 @@ namespace WebSocketSharp {
|
||||
}
|
||||
|
||||
// As server
|
||||
private void processRequestExtensions(string extensions)
|
||||
private void processRequestedExtensions (string extensions)
|
||||
{
|
||||
if (extensions.IsNullOrEmpty())
|
||||
return;
|
||||
|
||||
var comp = false;
|
||||
var buffer = new List<string> ();
|
||||
foreach (var extension in extensions.SplitHeaderValue(','))
|
||||
foreach (var e in extensions.SplitHeaderValue (','))
|
||||
{
|
||||
var e = extension.Trim();
|
||||
var tmp = e.RemovePrefix("x-webkit-");
|
||||
if (!comp && isCompressionExtension(tmp))
|
||||
var extension = e.Trim ();
|
||||
var tmp = extension.RemovePrefix ("x-webkit-");
|
||||
if (!comp && tmp.IsCompressionExtension ())
|
||||
{
|
||||
var method = getCompressionMethod(tmp);
|
||||
var method = tmp.ToCompressionMethod ();
|
||||
if (method != CompressionMethod.NONE)
|
||||
{
|
||||
_compression = method;
|
||||
comp = true;
|
||||
buffer.Add(e);
|
||||
buffer.Add (extension);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1052,102 +1023,32 @@ namespace WebSocketSharp {
|
||||
_extensions = buffer.ToArray ().ToString (", ");
|
||||
}
|
||||
|
||||
// As server
|
||||
private bool processHandshakeRequest ()
|
||||
{
|
||||
var req = HandshakeRequest.Parse (_context);
|
||||
_logger.Debug ("A handshake request from a client:\n" + req.ToString ());
|
||||
if (!isValidRequesHandshake ())
|
||||
{
|
||||
var msg = "Invalid WebSocket connection request.";
|
||||
_logger.Error (msg);
|
||||
error (msg);
|
||||
Close (HttpStatusCode.BadRequest);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
_base64key = _context.SecWebSocketKey;
|
||||
|
||||
var protocols = _context.Headers ["Sec-WebSocket-Protocol"];
|
||||
if (!protocols.IsNullOrEmpty ())
|
||||
_protocols = protocols;
|
||||
|
||||
processRequestExtensions (_context.Headers ["Sec-WebSocket-Extensions"]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// As client
|
||||
private void processResponseCookies(CookieCollection cookies)
|
||||
private void processRespondedExtensions (string extensions)
|
||||
{
|
||||
if (cookies.Count > 0)
|
||||
_cookies.SetOrRemove(cookies);
|
||||
}
|
||||
|
||||
// As client
|
||||
private void processResponseExtensions(string extensions)
|
||||
var comp = _compression != CompressionMethod.NONE ? true : false;
|
||||
var hasComp = false;
|
||||
if (extensions != null && extensions.Length > 0)
|
||||
{
|
||||
var checkComp = _compression != CompressionMethod.NONE
|
||||
? true
|
||||
: false;
|
||||
|
||||
var comp = false;
|
||||
if (!extensions.IsNullOrEmpty())
|
||||
foreach (var e in extensions.SplitHeaderValue (','))
|
||||
{
|
||||
foreach (var extension in extensions.SplitHeaderValue(','))
|
||||
{
|
||||
var e = extension.Trim();
|
||||
if (checkComp &&
|
||||
!comp &&
|
||||
isCompressionExtension(e, _compression))
|
||||
comp = true;
|
||||
var extension = e.Trim ();
|
||||
if (comp && !hasComp && extension.Equals (_compression))
|
||||
hasComp = true;
|
||||
}
|
||||
|
||||
_extensions = extensions;
|
||||
}
|
||||
|
||||
if (checkComp && !comp)
|
||||
if (comp && !hasComp)
|
||||
_compression = CompressionMethod.NONE;
|
||||
}
|
||||
|
||||
// As client
|
||||
private bool processHandshakeResponse (HandshakeResponse response)
|
||||
{
|
||||
var msg = response.IsUnauthorized
|
||||
? String.Format ("An HTTP {0} authorization is required.", response.AuthChallenge.Scheme)
|
||||
: !isValidHandshakeResponse (response)
|
||||
? "Invalid response to this WebSocket connection request."
|
||||
: String.Empty;
|
||||
|
||||
if (msg.Length > 0)
|
||||
{
|
||||
_logger.Error (msg);
|
||||
error (msg);
|
||||
Close (CloseStatusCode.ABNORMAL, msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
processResponseProtocol (response.Headers ["Sec-WebSocket-Protocol"]);
|
||||
processResponseExtensions (response.Headers ["Sec-WebSocket-Extensions"]);
|
||||
processResponseCookies (response.Cookies);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// As client
|
||||
private void processResponseProtocol(string protocol)
|
||||
{
|
||||
if (!protocol.IsNullOrEmpty())
|
||||
_protocol = protocol;
|
||||
}
|
||||
|
||||
// As client
|
||||
private HandshakeResponse receiveHandshakeResponse ()
|
||||
{
|
||||
var res = HandshakeResponse.Parse (_stream.ReadHandshake ());
|
||||
_logger.Debug ("A handshake response from the server:\n" + res.ToString ());
|
||||
_logger.Debug ("A response to this WebSocket connection request:\n" + res.ToString ());
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -1155,14 +1056,15 @@ namespace WebSocketSharp {
|
||||
// As client
|
||||
private void send (HandshakeRequest request)
|
||||
{
|
||||
_logger.Debug ("A handshake Request to the server:\n" + request.ToString ());
|
||||
_logger.Debug (String.Format ("A WebSocket connection request to {0}:\n{1}",
|
||||
_uri, request));
|
||||
_stream.WriteHandshake (request);
|
||||
}
|
||||
|
||||
// As server
|
||||
private bool send (HandshakeResponse response)
|
||||
{
|
||||
_logger.Debug ("A handshake response to a client:\n" + response.ToString ());
|
||||
_logger.Debug ("A response to a WebSocket connection request:\n" + response.ToString ());
|
||||
return _stream.WriteHandshake (response);
|
||||
}
|
||||
|
||||
@ -1195,8 +1097,7 @@ namespace WebSocketSharp {
|
||||
{
|
||||
var data = stream;
|
||||
var compressed = false;
|
||||
try
|
||||
{
|
||||
try {
|
||||
if (_readyState != WsState.OPEN)
|
||||
{
|
||||
var msg = "The WebSocket connection isn't established or has been closed.";
|
||||
@ -1221,13 +1122,11 @@ namespace WebSocketSharp {
|
||||
sendFragmented (opcode, data, compressed);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
catch (Exception ex) {
|
||||
_logger.Fatal (ex.Message);
|
||||
error ("An exception has occured.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
finally {
|
||||
if (compressed)
|
||||
data.Dispose ();
|
||||
|
||||
@ -1246,8 +1145,7 @@ namespace WebSocketSharp {
|
||||
Action<Opcode, Stream> sender = send;
|
||||
AsyncCallback callback = ar =>
|
||||
{
|
||||
try
|
||||
{
|
||||
try {
|
||||
sender.EndInvoke (ar);
|
||||
if (completed != null)
|
||||
completed ();
|
||||
@ -1359,6 +1257,42 @@ namespace WebSocketSharp {
|
||||
_stream.ReadFrameAsync (completed);
|
||||
}
|
||||
|
||||
// As server
|
||||
private bool validateConnectionRequest (WebSocketContext context)
|
||||
{
|
||||
return context.IsWebSocketRequest &&
|
||||
validateHostHeader (context.Host) &&
|
||||
!context.SecWebSocketKey.IsNullOrEmpty () &&
|
||||
context.Headers.Contains ("Sec-WebSocket-Version", _version);
|
||||
}
|
||||
|
||||
// As client
|
||||
private bool validateConnectionResponse (HandshakeResponse response)
|
||||
{
|
||||
return response.IsWebSocketResponse &&
|
||||
response.Headers.Contains ("Sec-WebSocket-Accept", createResponseKey ()) &&
|
||||
(!response.Headers.Contains ("Sec-WebSocket-Version") ||
|
||||
response.Headers.Contains ("Sec-WebSocket-Version", _version));
|
||||
}
|
||||
|
||||
// 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 type = Uri.CheckHostName (host);
|
||||
|
||||
return type != UriHostNameType.Dns ||
|
||||
Uri.CheckHostName (_uri.DnsSafeHost) != UriHostNameType.Dns ||
|
||||
host == _uri.DnsSafeHost;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Methods
|
||||
@ -1367,9 +1301,7 @@ namespace WebSocketSharp {
|
||||
internal void Close (HttpStatusCode code)
|
||||
{
|
||||
_readyState = WsState.CLOSING;
|
||||
send (createHandshakeResponse (code));
|
||||
closeResources ();
|
||||
_readyState = WsState.CLOSED;
|
||||
close (code);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -1469,13 +1401,11 @@ namespace WebSocketSharp {
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
if (connect ())
|
||||
open ();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
catch (Exception ex) {
|
||||
_logger.Fatal (ex.Message);
|
||||
var msg = "An exception has occured.";
|
||||
error (msg);
|
||||
|
Loading…
Reference in New Issue
Block a user