From 41f104e9237d0c1474aa2f4e1710f4f5ee3adec4 Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Tue, 9 Feb 2016 07:46:48 +0900 Subject: [PATCH 01/17] Support HTTP BASIC and DIGEST auth simultaneously --- websocket-sharp/Net/HttpListener.cs | 38 +++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/websocket-sharp/Net/HttpListener.cs b/websocket-sharp/Net/HttpListener.cs index 830fcd30c..274889412 100644 --- a/websocket-sharp/Net/HttpListener.cs +++ b/websocket-sharp/Net/HttpListener.cs @@ -401,6 +401,14 @@ public Func UserCredentialsFinder { #region Private Methods + private static bool HasFlag(Enum enumRef, Enum flag) + { + long value = Convert.ToInt64(enumRef); + long flagVal = Convert.ToInt64(flag); + + return (value & flagVal) == flagVal; + } + private void cleanup (bool force) { lock (_ctxRegistrySync) { @@ -509,26 +517,40 @@ internal bool Authenticate (HttpListenerContext context) if (schm == AuthenticationSchemes.Anonymous) return true; - if (schm != AuthenticationSchemes.Basic && schm != AuthenticationSchemes.Digest) { + var basicAllowed = HasFlag(schm, AuthenticationSchemes.Basic); + var digestAllowed = HasFlag(schm, AuthenticationSchemes.Digest); + if (!basicAllowed && !digestAllowed) { context.Response.Close (HttpStatusCode.Forbidden); return false; } var realm = Realm; var req = context.Request; - var user = HttpUtility.CreateUser ( - req.Headers["Authorization"], schm, realm, req.HttpMethod, UserCredentialsFinder); + if (basicAllowed) { + var user = HttpUtility.CreateUser( + req.Headers["Authorization"], AuthenticationSchemes.Basic, realm, req.HttpMethod, UserCredentialsFinder); - if (user != null && user.Identity.IsAuthenticated) { - context.User = user; - return true; + if (user != null && user.Identity.IsAuthenticated) { + context.User = user; + return true; + } + } + + if (digestAllowed) { + var user = HttpUtility.CreateUser( + req.Headers["Authorization"], AuthenticationSchemes.Digest, realm, req.HttpMethod, UserCredentialsFinder); + + if (user != null && user.Identity.IsAuthenticated) { + context.User = user; + return true; + } } - if (schm == AuthenticationSchemes.Basic) + if (!digestAllowed) context.Response.CloseWithAuthChallenge ( AuthenticationChallenge.CreateBasicChallenge (realm).ToBasicString ()); - if (schm == AuthenticationSchemes.Digest) + else context.Response.CloseWithAuthChallenge ( AuthenticationChallenge.CreateDigestChallenge (realm).ToDigestString ()); From 35cb678a097e8ce50d462b57ea6046730ca172d6 Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Tue, 9 Feb 2016 07:47:18 +0900 Subject: [PATCH 02/17] Support a custom server header when the request is handled entirely by the library (i.e. authorisation failure) --- websocket-sharp/Net/HttpListener.cs | 12 ++++++++++++ websocket-sharp/Net/HttpListenerResponse.cs | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/websocket-sharp/Net/HttpListener.cs b/websocket-sharp/Net/HttpListener.cs index 274889412..a4338d3de 100644 --- a/websocket-sharp/Net/HttpListener.cs +++ b/websocket-sharp/Net/HttpListener.cs @@ -110,6 +110,11 @@ public HttpListener () _waitQueueSync = ((ICollection) _waitQueue).SyncRoot; } + static HttpListener() + { + DefaultServerString = "websocket-sharp/1.0"; + } + #endregion #region Internal Properties @@ -134,6 +139,13 @@ internal bool ReuseAddress { #region Public Properties + /// + /// Gets or sets the server string to include in the response when a + /// request is handled entirely by the library and not by any user + /// callbacks + /// + public static string DefaultServerString { get; set; } + /// /// Gets or sets the scheme used to authenticate the clients. /// diff --git a/websocket-sharp/Net/HttpListenerResponse.cs b/websocket-sharp/Net/HttpListenerResponse.cs index 92c0a7970..272a98355 100644 --- a/websocket-sharp/Net/HttpListenerResponse.cs +++ b/websocket-sharp/Net/HttpListenerResponse.cs @@ -515,7 +515,7 @@ internal WebHeaderCollection WriteHeadersTo (MemoryStream destination) } if (headers["Server"] == null) - headers.InternalSet ("Server", "websocket-sharp/1.0", true); + headers.InternalSet ("Server", HttpListener.DefaultServerString, true); var prov = CultureInfo.InvariantCulture; if (headers["Date"] == null) From a79bd82764eb16467373ae52ac13bf741868bded Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Tue, 9 Feb 2016 14:25:12 +0900 Subject: [PATCH 03/17] Refactored project so that it can be deployed to Xamarin as well. --- Example/Example.csproj | 8 +- Example1/Example1.csproj | 13 +-- Example2/Example2.csproj | 4 +- Example3/Example3.csproj | 4 +- websocket-sharp.sln | 28 +++++- websocket-sharp/websocket-sharp.csproj | 97 +------------------ websocket-sharp/websocket-sharp.droid.csproj | 45 +++++++++ websocket-sharp/websocket-sharp.ios.csproj | 42 ++++++++ .../websocket-sharp.shared.projitems | 92 ++++++++++++++++++ websocket-sharp/websocket-sharp.shared.shproj | 11 +++ 10 files changed, 227 insertions(+), 117 deletions(-) create mode 100644 websocket-sharp/websocket-sharp.droid.csproj create mode 100644 websocket-sharp/websocket-sharp.ios.csproj create mode 100644 websocket-sharp/websocket-sharp.shared.projitems create mode 100644 websocket-sharp/websocket-sharp.shared.shproj diff --git a/Example/Example.csproj b/Example/Example.csproj index 38c5b4200..12500071f 100644 --- a/Example/Example.csproj +++ b/Example/Example.csproj @@ -1,10 +1,8 @@ - + Debug AnyCPU - 9.0.21022 - 2.0 {52805AEC-EFB1-4F42-BB8E-3ED4E692C568} Exe Example @@ -50,9 +48,7 @@ - - notify-sharp - + diff --git a/Example1/Example1.csproj b/Example1/Example1.csproj index 903f5b045..578019eef 100644 --- a/Example1/Example1.csproj +++ b/Example1/Example1.csproj @@ -1,10 +1,8 @@ - + Debug AnyCPU - 9.0.21022 - 2.0 {390E2568-57B7-4D17-91E5-C29336368CCF} Exe Example @@ -50,13 +48,8 @@ - - False - notify-sharp - - - False - + + diff --git a/Example2/Example2.csproj b/Example2/Example2.csproj index 685a1ef6d..87fda0976 100644 --- a/Example2/Example2.csproj +++ b/Example2/Example2.csproj @@ -1,10 +1,8 @@ - + Debug AnyCPU - 9.0.21022 - 2.0 {B81A24C8-25BB-42B2-AF99-1E1EACCE74C7} Exe Example2 diff --git a/Example3/Example3.csproj b/Example3/Example3.csproj index ce4fe265c..43e86f230 100644 --- a/Example3/Example3.csproj +++ b/Example3/Example3.csproj @@ -1,10 +1,8 @@ - + Debug AnyCPU - 9.0.21022 - 2.0 {C648BA25-77E5-4A40-A97F-D0AA37B9FB26} Exe Example3 diff --git a/websocket-sharp.sln b/websocket-sharp.sln index 3c20e06a0..06c7e91d3 100644 --- a/websocket-sharp.sln +++ b/websocket-sharp.sln @@ -1,6 +1,6 @@  -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "websocket-sharp", "websocket-sharp\websocket-sharp.csproj", "{B357BAC7-529E-4D81-A0D2-71041B19C8DE}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}" @@ -11,6 +11,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example2", "Example2\Exampl EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example3", "Example3\Example3.csproj", "{C648BA25-77E5-4A40-A97F-D0AA37B9FB26}" EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "websocket-sharp.shared", "websocket-sharp\websocket-sharp.shared.shproj", "{891A08FC-F143-4325-BC16-B9864D036B99}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "websocket-sharp.droid", "websocket-sharp\websocket-sharp.droid.csproj", "{E1153FA4-356A-454D-B32E-136102F2482F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "websocket-sharp.ios", "websocket-sharp\websocket-sharp.ios.csproj", "{DCE46CB2-0317-4A62-9613-AE6A240C46DB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -59,9 +65,24 @@ Global {C648BA25-77E5-4A40-A97F-D0AA37B9FB26}.Release_Ubuntu|Any CPU.Build.0 = Release_Ubuntu|Any CPU {C648BA25-77E5-4A40-A97F-D0AA37B9FB26}.Release|Any CPU.ActiveCfg = Release|Any CPU {C648BA25-77E5-4A40-A97F-D0AA37B9FB26}.Release|Any CPU.Build.0 = Release|Any CPU + {DCE46CB2-0317-4A62-9613-AE6A240C46DB}.Debug_Ubuntu|Any CPU.ActiveCfg = Debug|Any CPU + {DCE46CB2-0317-4A62-9613-AE6A240C46DB}.Debug_Ubuntu|Any CPU.Build.0 = Debug|Any CPU + {DCE46CB2-0317-4A62-9613-AE6A240C46DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DCE46CB2-0317-4A62-9613-AE6A240C46DB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DCE46CB2-0317-4A62-9613-AE6A240C46DB}.Release_Ubuntu|Any CPU.ActiveCfg = Release|Any CPU + {DCE46CB2-0317-4A62-9613-AE6A240C46DB}.Release_Ubuntu|Any CPU.Build.0 = Release|Any CPU + {DCE46CB2-0317-4A62-9613-AE6A240C46DB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DCE46CB2-0317-4A62-9613-AE6A240C46DB}.Release|Any CPU.Build.0 = Release|Any CPU + {E1153FA4-356A-454D-B32E-136102F2482F}.Debug_Ubuntu|Any CPU.ActiveCfg = Debug|Any CPU + {E1153FA4-356A-454D-B32E-136102F2482F}.Debug_Ubuntu|Any CPU.Build.0 = Debug|Any CPU + {E1153FA4-356A-454D-B32E-136102F2482F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E1153FA4-356A-454D-B32E-136102F2482F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E1153FA4-356A-454D-B32E-136102F2482F}.Release_Ubuntu|Any CPU.ActiveCfg = Release|Any CPU + {E1153FA4-356A-454D-B32E-136102F2482F}.Release_Ubuntu|Any CPU.Build.0 = Release|Any CPU + {E1153FA4-356A-454D-B32E-136102F2482F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E1153FA4-356A-454D-B32E-136102F2482F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution - StartupItem = websocket-sharp\websocket-sharp.csproj Policies = $0 $0.TextStylePolicy = $1 $1.inheritsSet = null @@ -70,5 +91,6 @@ Global $2.inheritsSet = Mono $2.inheritsScope = text/x-csharp $2.scope = text/x-csharp + StartupItem = websocket-sharp\websocket-sharp.csproj EndGlobalSection EndGlobal diff --git a/websocket-sharp/websocket-sharp.csproj b/websocket-sharp/websocket-sharp.csproj index 087679547..702aea1d3 100644 --- a/websocket-sharp/websocket-sharp.csproj +++ b/websocket-sharp/websocket-sharp.csproj @@ -1,16 +1,14 @@ - + Debug AnyCPU - 9.0.21022 - 2.0 {B357BAC7-529E-4D81-A0D2-71041B19C8DE} Library WebSocketSharp websocket-sharp v3.5 - true + false websocket-sharp.snk @@ -48,103 +46,18 @@ prompt 4 false - true - + + bin\Release_Ubuntu\websocket-sharp.xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - \ No newline at end of file diff --git a/websocket-sharp/websocket-sharp.droid.csproj b/websocket-sharp/websocket-sharp.droid.csproj new file mode 100644 index 000000000..5c02b0d34 --- /dev/null +++ b/websocket-sharp/websocket-sharp.droid.csproj @@ -0,0 +1,45 @@ + + + + Debug + AnyCPU + {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + {E1153FA4-356A-454D-B32E-136102F2482F} + Library + websocketsharp.droid + Assets + Resources + Resource + Resources\Resource.designer.cs + False + websocket-sharp.droid + 1.1.1 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + None + false + + + true + bin\Release + prompt + 4 + false + false + + + + + + + + + + \ No newline at end of file diff --git a/websocket-sharp/websocket-sharp.ios.csproj b/websocket-sharp/websocket-sharp.ios.csproj new file mode 100644 index 000000000..c7971fefb --- /dev/null +++ b/websocket-sharp/websocket-sharp.ios.csproj @@ -0,0 +1,42 @@ + + + + Debug + AnyCPU + {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + {DCE46CB2-0317-4A62-9613-AE6A240C46DB} + Library + websocketsharp.ios + Resources + websocket-sharp.ios + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + + + full + true + bin\Release + prompt + 4 + false + + + + + + + + + + + + + \ No newline at end of file diff --git a/websocket-sharp/websocket-sharp.shared.projitems b/websocket-sharp/websocket-sharp.shared.projitems new file mode 100644 index 000000000..c6f558b96 --- /dev/null +++ b/websocket-sharp/websocket-sharp.shared.projitems @@ -0,0 +1,92 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + {891A08FC-F143-4325-BC16-B9864D036B99} + + + websocket-sharp.shared + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/websocket-sharp/websocket-sharp.shared.shproj b/websocket-sharp/websocket-sharp.shared.shproj new file mode 100644 index 000000000..90eb1e6c7 --- /dev/null +++ b/websocket-sharp/websocket-sharp.shared.shproj @@ -0,0 +1,11 @@ + + + + {891A08FC-F143-4325-BC16-B9864D036B99} + + + + + + + \ No newline at end of file From a7f85e780017f5dad47499d0ecb95f6e8a0cf6c3 Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Fri, 12 Feb 2016 11:17:05 +0900 Subject: [PATCH 04/17] Make the HttpConnection construction asynchronous to try to free up some of the locking burden (still limited on how many it can process at once, unfortunately) --- websocket-sharp/Net/EndPointListener.cs | 32 ++++----- websocket-sharp/Net/HttpConnection.cs | 90 ++++++++++++++++++------- websocket-sharp/websocket-sharp.csproj | 4 +- 3 files changed, 83 insertions(+), 43 deletions(-) diff --git a/websocket-sharp/Net/EndPointListener.cs b/websocket-sharp/Net/EndPointListener.cs index 936f81d06..72b35d66d 100644 --- a/websocket-sharp/Net/EndPointListener.cs +++ b/websocket-sharp/Net/EndPointListener.cs @@ -257,22 +257,22 @@ private static void onAccept (IAsyncResult asyncResult) private static void processAccepted (Socket socket, EndPointListener listener) { - HttpConnection conn = null; - try { - conn = new HttpConnection (socket, listener); - lock (listener._unregisteredSync) - listener._unregistered[conn] = conn; - - conn.BeginReadRequest (); - } - catch { - if (conn != null) { - conn.Close (true); - return; - } - - socket.Close (); - } + HttpConnection.CreateAsync(socket, listener, conn => + { + try { + lock (listener._unregisteredSync) + listener._unregistered[conn] = conn; + + conn.BeginReadRequest (); + } catch(Exception e) { + if (conn != null) { + conn.Close (true); + return; + } + + socket.Close (); + } + }); } private static bool removeSpecial (List prefixes, HttpListenerPrefix prefix) diff --git a/websocket-sharp/Net/HttpConnection.cs b/websocket-sharp/Net/HttpConnection.cs index 3527731ed..c55b9061d 100644 --- a/websocket-sharp/Net/HttpConnection.cs +++ b/websocket-sharp/Net/HttpConnection.cs @@ -28,6 +28,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + #endregion #region Authors @@ -57,6 +58,23 @@ namespace WebSocketSharp.Net { internal sealed class HttpConnection { + + #region Private Classes + + private class HttpSecureConnectionState + { + public readonly HttpConnection Connection; + public readonly Action Callback; + + public HttpSecureConnectionState(HttpConnection connection, Action callback) + { + Connection = connection; + Callback = callback; + } + } + + #endregion + #region Private Fields private byte[] _buffer; @@ -83,35 +101,13 @@ internal sealed class HttpConnection #endregion - #region Internal Constructors - internal HttpConnection (Socket socket, EndPointListener listener) - { - _socket = socket; - _listener = listener; - _secure = listener.IsSecure; - - var netStream = new NetworkStream (socket, false); - if (_secure) { - var conf = listener.SslConfiguration; - var sslStream = new SslStream (netStream, false, conf.ClientCertificateValidationCallback); - sslStream.AuthenticateAsServer ( - conf.ServerCertificate, - conf.ClientCertificateRequired, - conf.EnabledSslProtocols, - conf.CheckCertificateRevocation); - - _stream = sslStream; - } - else { - _stream = netStream; - } - _sync = new object (); - _timeout = 90000; // 90k ms for first request, 15k ms from then on. - _timer = new Timer (onTimeout, this, Timeout.Infinite, Timeout.Infinite); + #region Constructors + + private HttpConnection() + { - init (); } #endregion @@ -168,6 +164,28 @@ public Stream Stream { #region Private Methods + // SSL handshake is ready to be processed + private static void FinishAuth(IAsyncResult result) + { + var state = result.AsyncState as HttpSecureConnectionState; + var stream = state.Connection.Stream as SslStream; + stream.EndAuthenticateAsServer(result); + FinishSetup(state.Connection, state.Callback); + } + + // Connection is ready to be used + private static void FinishSetup(HttpConnection connection, Action callback) + { + connection._sync = new object(); + connection._timeout = 90000; // 90k ms for first request, 15k ms from then on. + connection._timer = new Timer (onTimeout, connection, Timeout.Infinite, Timeout.Infinite); + + connection.init (); + if (callback != null) { + callback(connection); + } + } + private void close () { lock (_sync) { @@ -443,6 +461,26 @@ internal void Close (bool force) #region Public Methods + public static void CreateAsync(Socket socket, EndPointListener listener, Action callback) + { + var retVal = new HttpConnection(); + retVal._socket = socket; + retVal._listener = listener; + retVal._secure = listener.IsSecure; + + + if (!listener.IsSecure) { + retVal._stream = new NetworkStream (socket, false); + FinishSetup(retVal, callback); + } else { + var netStream = new NetworkStream (socket, false); + var conf = listener.SslConfiguration; + var sslStream = new SslStream (netStream, false, conf.ClientCertificateValidationCallback); + retVal._stream = sslStream; + sslStream.BeginAuthenticateAsServer(conf.ServerCertificate, FinishAuth, new HttpSecureConnectionState(retVal, callback)); + } + } + public void BeginReadRequest () { if (_buffer == null) diff --git a/websocket-sharp/websocket-sharp.csproj b/websocket-sharp/websocket-sharp.csproj index 702aea1d3..7519517a3 100644 --- a/websocket-sharp/websocket-sharp.csproj +++ b/websocket-sharp/websocket-sharp.csproj @@ -10,6 +10,7 @@ v3.5 false websocket-sharp.snk + 1.1.1 true @@ -22,12 +23,13 @@ false - none + pdbonly false bin\Release prompt 4 false + true true From e79b638bdc29534a99adc4e079c41fe2d146bc94 Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Sat, 20 Feb 2016 18:50:29 +0900 Subject: [PATCH 05/17] Prevent an exception from crashing the thread when SSL auth fails --- websocket-sharp/Net/HttpConnection.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/websocket-sharp/Net/HttpConnection.cs b/websocket-sharp/Net/HttpConnection.cs index c55b9061d..fccdfcbd5 100644 --- a/websocket-sharp/Net/HttpConnection.cs +++ b/websocket-sharp/Net/HttpConnection.cs @@ -169,7 +169,11 @@ private static void FinishAuth(IAsyncResult result) { var state = result.AsyncState as HttpSecureConnectionState; var stream = state.Connection.Stream as SslStream; - stream.EndAuthenticateAsServer(result); + try { + stream.EndAuthenticateAsServer(result); + } catch(IOException) { + stream.Close(); + } FinishSetup(state.Connection, state.Callback); } From ed7a283cb0d2fa67c2f67f218aee413a7bc3a913 Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Wed, 23 Mar 2016 11:49:28 +0900 Subject: [PATCH 06/17] Fix a bug in which restarting HttpListener quickly will cause 400 BAD REQUEST --- websocket-sharp/Net/HttpListener.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/websocket-sharp/Net/HttpListener.cs b/websocket-sharp/Net/HttpListener.cs index a4338d3de..0ec1c4717 100644 --- a/websocket-sharp/Net/HttpListener.cs +++ b/websocket-sharp/Net/HttpListener.cs @@ -435,18 +435,20 @@ private void cleanup (bool force) private void cleanupConnections () { + var conns = default(HttpConnection[]); lock (_connectionsSync) { if (_connections.Count == 0) return; // Need to copy this since closing will call the RemoveConnection method. var keys = _connections.Keys; - var conns = new HttpConnection[keys.Count]; + conns = new HttpConnection[keys.Count]; keys.CopyTo (conns, 0); _connections.Clear (); - for (var i = conns.Length - 1; i >= 0; i--) - conns[i].Close (true); } + + for (var i = conns.Length - 1; i >= 0; i--) + conns[i].Close (true); } private void cleanupContextRegistry () @@ -818,6 +820,7 @@ public void Stop () _listening = false; EndPointManager.RemoveListener (this); sendServiceUnavailable (); + cleanupConnections(); } #endregion From ef5b725335a0eb241e0ce3f9b1cbb26fc7c4dfcf Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Thu, 7 Apr 2016 10:27:40 +0900 Subject: [PATCH 07/17] Change target framework to ICS and change output DLL name to match others --- websocket-sharp/websocket-sharp.droid.csproj | 3 ++- websocket-sharp/websocket-sharp.ios.csproj | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/websocket-sharp/websocket-sharp.droid.csproj b/websocket-sharp/websocket-sharp.droid.csproj index 5c02b0d34..05138f74e 100644 --- a/websocket-sharp/websocket-sharp.droid.csproj +++ b/websocket-sharp/websocket-sharp.droid.csproj @@ -12,8 +12,9 @@ Resource Resources\Resource.designer.cs False - websocket-sharp.droid + websocket-sharp 1.1.1 + v4.0.3 true diff --git a/websocket-sharp/websocket-sharp.ios.csproj b/websocket-sharp/websocket-sharp.ios.csproj index c7971fefb..4eed0c610 100644 --- a/websocket-sharp/websocket-sharp.ios.csproj +++ b/websocket-sharp/websocket-sharp.ios.csproj @@ -8,7 +8,8 @@ Library websocketsharp.ios Resources - websocket-sharp.ios + websocket-sharp + 1.1.1 true From 513a46a34996cd40da925647d27d8768a8588fe6 Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Fri, 8 Apr 2016 10:42:15 +0900 Subject: [PATCH 08/17] Output symbols --- websocket-sharp/websocket-sharp.droid.csproj | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/websocket-sharp/websocket-sharp.droid.csproj b/websocket-sharp/websocket-sharp.droid.csproj index 05138f74e..cf365d844 100644 --- a/websocket-sharp/websocket-sharp.droid.csproj +++ b/websocket-sharp/websocket-sharp.droid.csproj @@ -1,4 +1,4 @@ - + Debug @@ -34,6 +34,8 @@ 4 false false + pdbonly + true From 516cc8b7ac550ebade777a197e63f7ab81150fb5 Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Fri, 8 Apr 2016 11:19:59 +0900 Subject: [PATCH 09/17] iOS also needs proper symbol output --- websocket-sharp/websocket-sharp.ios.csproj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/websocket-sharp/websocket-sharp.ios.csproj b/websocket-sharp/websocket-sharp.ios.csproj index 4eed0c610..2e9411ec3 100644 --- a/websocket-sharp/websocket-sharp.ios.csproj +++ b/websocket-sharp/websocket-sharp.ios.csproj @@ -1,4 +1,4 @@ - + Debug @@ -22,12 +22,13 @@ false - full + pdbonly true bin\Release prompt 4 false + true From 49d906055eada9838a1be122a1a9c589532e2b41 Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Wed, 25 May 2016 07:09:29 +0900 Subject: [PATCH 10/17] Remove unused configs --- websocket-sharp/websocket-sharp.csproj | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/websocket-sharp/websocket-sharp.csproj b/websocket-sharp/websocket-sharp.csproj index 7519517a3..3cd7fb1ec 100644 --- a/websocket-sharp/websocket-sharp.csproj +++ b/websocket-sharp/websocket-sharp.csproj @@ -1,4 +1,4 @@ - + Debug @@ -31,30 +31,6 @@ false true - - true - full - false - bin\Debug_Ubuntu - DEBUG - prompt - 4 - false - - - none - false - bin\Release_Ubuntu - prompt - 4 - false - - - - - - bin\Release_Ubuntu\websocket-sharp.xml - From 75bb252656397a41da61451501aa87910ceb38ff Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Fri, 3 Jun 2016 15:38:05 +0900 Subject: [PATCH 11/17] Add custom headers property to allow some authenticator logic in web sockets (addresses an issue with authentication and web sockets) --- websocket-sharp/WebSocket.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/websocket-sharp/WebSocket.cs b/websocket-sharp/WebSocket.cs index 68a6df209..4c22b91e2 100644 --- a/websocket-sharp/WebSocket.cs +++ b/websocket-sharp/WebSocket.cs @@ -295,6 +295,9 @@ internal bool IsConnected { #region Public Properties + + public IEnumerable> CustomHeaders { get; set; } + /// /// Gets or sets the compression method used to compress a message on the WebSocket connection. /// @@ -955,6 +958,12 @@ private HttpRequest createHandshakeRequest () if (authRes != null) headers["Authorization"] = authRes.ToString (); + if (CustomHeaders != null) { + foreach (var header in CustomHeaders) { + headers[header.Key] = header.Value; + } + } + if (_cookies.Count > 0) ret.SetCookies (_cookies); From b0488483867cb078c7ba4c4003f43562116fcd9f Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Thu, 23 Jun 2016 19:09:36 +0900 Subject: [PATCH 12/17] Reverted to sync SSL processing so exceptions don't get accidentally swallowed without closing the socket --- websocket-sharp/Net/EndPointListener.cs | 19 +++--- websocket-sharp/Net/HttpConnection.cs | 88 ++++++++++--------------- 2 files changed, 42 insertions(+), 65 deletions(-) diff --git a/websocket-sharp/Net/EndPointListener.cs b/websocket-sharp/Net/EndPointListener.cs index 72b35d66d..cec056052 100644 --- a/websocket-sharp/Net/EndPointListener.cs +++ b/websocket-sharp/Net/EndPointListener.cs @@ -257,23 +257,22 @@ private static void onAccept (IAsyncResult asyncResult) private static void processAccepted (Socket socket, EndPointListener listener) { - HttpConnection.CreateAsync(socket, listener, conn => - { + HttpConnection conn = null; try { - lock (listener._unregisteredSync) + conn = new HttpConnection(socket, listener); + lock(listener._unregisteredSync) listener._unregistered[conn] = conn; - conn.BeginReadRequest (); - } catch(Exception e) { - if (conn != null) { - conn.Close (true); + conn.BeginReadRequest(); + } catch { + if(conn != null) { + conn.Close(true); return; } - socket.Close (); + socket.Close(); } - }); - } + } private static bool removeSpecial (List prefixes, HttpListenerPrefix prefix) { diff --git a/websocket-sharp/Net/HttpConnection.cs b/websocket-sharp/Net/HttpConnection.cs index fccdfcbd5..9f1f66eda 100644 --- a/websocket-sharp/Net/HttpConnection.cs +++ b/websocket-sharp/Net/HttpConnection.cs @@ -99,22 +99,46 @@ public HttpSecureConnectionState(HttpConnection connection, Action callback) - { - connection._sync = new object(); - connection._timeout = 90000; // 90k ms for first request, 15k ms from then on. - connection._timer = new Timer (onTimeout, connection, Timeout.Infinite, Timeout.Infinite); - - connection.init (); - if (callback != null) { - callback(connection); - } - } - private void close () { lock (_sync) { @@ -465,26 +463,6 @@ internal void Close (bool force) #region Public Methods - public static void CreateAsync(Socket socket, EndPointListener listener, Action callback) - { - var retVal = new HttpConnection(); - retVal._socket = socket; - retVal._listener = listener; - retVal._secure = listener.IsSecure; - - - if (!listener.IsSecure) { - retVal._stream = new NetworkStream (socket, false); - FinishSetup(retVal, callback); - } else { - var netStream = new NetworkStream (socket, false); - var conf = listener.SslConfiguration; - var sslStream = new SslStream (netStream, false, conf.ClientCertificateValidationCallback); - retVal._stream = sslStream; - sslStream.BeginAuthenticateAsServer(conf.ServerCertificate, FinishAuth, new HttpSecureConnectionState(retVal, callback)); - } - } - public void BeginReadRequest () { if (_buffer == null) From aceec1662286c0366f092572e3c8ac4f652ecc5b Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Fri, 1 Jul 2016 11:18:11 +0400 Subject: [PATCH 13/17] Pulled enhancement from downstream preventing socket closure when an exception occurs during the acceptance process --- websocket-sharp/Net/EndPointListener.cs | 43 +++++++++++++++++-------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/websocket-sharp/Net/EndPointListener.cs b/websocket-sharp/Net/EndPointListener.cs index cec056052..a53831fb1 100644 --- a/websocket-sharp/Net/EndPointListener.cs +++ b/websocket-sharp/Net/EndPointListener.cs @@ -238,22 +238,39 @@ private static HttpListener matchFromList ( private static void onAccept (IAsyncResult asyncResult) { - var lsnr = (EndPointListener) asyncResult.AsyncState; + var lsnr = (EndPointListener)asyncResult.AsyncState; - Socket sock = null; - try { - sock = lsnr._socket.EndAccept (asyncResult); - lsnr._socket.BeginAccept (onAccept, lsnr); - } - catch { - if (sock != null) - sock.Close (); + Socket sock = null; + try + { + sock = lsnr._socket.EndAccept(asyncResult); + } + catch (SocketException) + { + // TODO: Should log the error code when this class has a logging. + } + catch (ObjectDisposedException) + { + return; + } - return; - } + try + { + lsnr._socket.BeginAccept(onAccept, lsnr); + } + catch + { + if (sock != null) + sock.Close(); - processAccepted (sock, lsnr); - } + return; + } + + if (sock == null) + return; + + processAccepted(sock, lsnr); + } private static void processAccepted (Socket socket, EndPointListener listener) { From f1452b41028e4d667187968036365a7d1d5bb5f8 Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Wed, 27 Jul 2016 08:17:31 -0400 Subject: [PATCH 14/17] Pin android build tools version to 23.0.3 --- websocket-sharp/websocket-sharp.droid.csproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/websocket-sharp/websocket-sharp.droid.csproj b/websocket-sharp/websocket-sharp.droid.csproj index cf365d844..d1b8da638 100644 --- a/websocket-sharp/websocket-sharp.droid.csproj +++ b/websocket-sharp/websocket-sharp.droid.csproj @@ -11,9 +11,10 @@ Resources Resource Resources\Resource.designer.cs - False + true websocket-sharp 1.1.1 + 23.0.3 v4.0.3 From 2b3e69af0eb90238fe9317cb077b28833d1a4f2e Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Thu, 4 Aug 2016 08:46:24 -0400 Subject: [PATCH 15/17] Build with the latest Android SDK --- websocket-sharp/websocket-sharp.droid.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/websocket-sharp/websocket-sharp.droid.csproj b/websocket-sharp/websocket-sharp.droid.csproj index d1b8da638..585060072 100644 --- a/websocket-sharp/websocket-sharp.droid.csproj +++ b/websocket-sharp/websocket-sharp.droid.csproj @@ -15,7 +15,7 @@ websocket-sharp 1.1.1 23.0.3 - v4.0.3 + v6.0 true From a1551a9ea22a2d14de5c89df1a0e144884ad8cfe Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Fri, 3 Feb 2017 11:00:24 +0900 Subject: [PATCH 16/17] Work around Sync Gateway not responding to close requests --- websocket-sharp/Ext.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/websocket-sharp/Ext.cs b/websocket-sharp/Ext.cs index 7c43986bb..6df0d1417 100644 --- a/websocket-sharp/Ext.cs +++ b/websocket-sharp/Ext.cs @@ -691,6 +691,10 @@ internal static void ReadBytesAsync ( stream.BeginRead (buff, offset, length, callback, null); } + catch(ObjectDisposedException) { + var hack = new WebSocketFrame(Opcode.Close, PayloadData.Empty, false); + completed(hack.ToArray()); + } catch (Exception ex) { if (error != null) error (ex); From f7e3bbb79e0d224a0f659098972141a235da21a1 Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Sat, 4 Feb 2017 15:09:59 +0900 Subject: [PATCH 17/17] Fix the concurrent basic / digest auth logic that got reverted as part of the merge from upstream --- websocket-sharp/Net/HttpListenerContext.cs | 55 +++++++++++++++------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/websocket-sharp/Net/HttpListenerContext.cs b/websocket-sharp/Net/HttpListenerContext.cs index 638078d4f..85bf15388 100644 --- a/websocket-sharp/Net/HttpListenerContext.cs +++ b/websocket-sharp/Net/HttpListenerContext.cs @@ -165,34 +165,53 @@ public IPrincipal User { #region Internal Methods + private static bool HasFlag(Enum enumRef, Enum flag) + { + long value = Convert.ToInt64(enumRef); + long flagVal = Convert.ToInt64(flag); + + return (value & flagVal) == flagVal; + } + internal bool Authenticate () { var schm = _listener.SelectAuthenticationScheme (_request); if (schm == AuthenticationSchemes.Anonymous) return true; - if (schm == AuthenticationSchemes.None) { - _response.Close (HttpStatusCode.Forbidden); - return false; + var basicAllowed = HasFlag(schm, AuthenticationSchemes.Basic); + var digestAllowed = HasFlag(schm, AuthenticationSchemes.Digest); + if(!basicAllowed && !digestAllowed) { + _response.Close(HttpStatusCode.Forbidden); + return false; + } + + var realm = _listener.GetRealm(); + if(basicAllowed) { + var user = HttpUtility.CreateUser(_request.Headers["Authorization"], AuthenticationSchemes.Basic, realm, + _request.HttpMethod, _listener.GetUserCredentialsFinder()); + if(user?.Identity?.IsAuthenticated == true) { + _user = user; + return true; + } + } + + if(digestAllowed) { + var user = HttpUtility.CreateUser(_request.Headers["Authorization"], AuthenticationSchemes.Digest, realm, + _request.HttpMethod, _listener.GetUserCredentialsFinder()); + if(user?.Identity?.IsAuthenticated == true) { + _user = user; + return true; + } } - var realm = _listener.GetRealm (); - var user = - HttpUtility.CreateUser ( - _request.Headers["Authorization"], - schm, - realm, - _request.HttpMethod, - _listener.GetUserCredentialsFinder () - ); - - if (user == null || !user.Identity.IsAuthenticated) { - _response.CloseWithAuthChallenge (new AuthenticationChallenge (schm, realm).ToString ()); - return false; + if(!digestAllowed) { + _response.CloseWithAuthChallenge(AuthenticationChallenge.CreateBasicChallenge(realm).ToBasicString()); + } else { + _response.CloseWithAuthChallenge(AuthenticationChallenge.CreateDigestChallenge(realm).ToDigestString()); } - _user = user; - return true; + return false; } internal bool Register ()