public void UnderstandEncodedCookies() { var handshaker = new WebSocketHandshaker(this.factories, new WebSocketListenerOptions { Logger = this.logger }); using (var connectionInput = new MemoryStream()) using (var connectionOutput = new MemoryStream()) using (var connection = new DummyNetworkConnection(connectionInput, connectionOutput)) { using (var sw = new StreamWriter(connectionInput, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Upgrade: websocket"); sw.WriteLine(@"Connection: Upgrade"); sw.WriteLine(@"Cookie: key=This%20is%20encoded."); sw.WriteLine(@"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw=="); sw.WriteLine(@"Sec-WebSocket-Version: 13"); sw.WriteLine(@"Origin: http://example.com"); } connectionInput.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(connection).Result; Assert.NotNull(result); Assert.True((bool)result.IsValidWebSocketRequest); Assert.Equal(1, result.Request.Cookies.Count); Assert.Equal((string)"This is encoded.", (string)result.Request.Cookies["key"].Value); } }
public void WebSocketHandshaker_CanParseMultipleCookie() { WebSocketHandshaker handshaker = new WebSocketHandshaker(_factories, new WebSocketListenerOptions() { }); using (var ms = new MemoryStream()) { using (var sw = new StreamWriter(ms, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Upgrade: websocket"); sw.WriteLine(@"Connection: Upgrade"); sw.WriteLine(@"Cookie: cookie1=uno; cookie2=dos"); sw.WriteLine(@"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw=="); sw.WriteLine(@"Sec-WebSocket-Version: 13"); sw.WriteLine(@"Origin: http://example.com"); } var position = ms.Position; ms.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(ms).Result; Assert.NotNull(result); Assert.AreEqual(2, result.Request.Cookies.Count); } }
private async Task NegotiateWebSocket(Socket client) { WebSocketNegotiationResult result; try { var timeoutTask = Task.Delay(_options.NegotiationTimeout); #if (NET45 || NET451 || NET452 || NET46) Stream stream = new NetworkStream(client, FileAccess.ReadWrite, true); #elif (DNX451 || DNX452 || DNX46 || NETSTANDARD || UAP10_0 || DOTNET5_4 || NETSTANDARDAPP1_5) Stream stream = new NetworkStream(client); #endif foreach (var conExt in _extensions) { var extTask = conExt.ExtendConnectionAsync(stream); await Task.WhenAny(timeoutTask, extTask).ConfigureAwait(false); if (timeoutTask.IsCompleted) { throw new WebSocketException("Negotiation timeout (Extension: " + conExt.GetType().Name + ")"); } stream = await extTask; } var handshakeTask = _handShaker.HandshakeAsync(stream); await Task.WhenAny(timeoutTask, handshakeTask).ConfigureAwait(false); if (timeoutTask.IsCompleted) { throw new WebSocketException("Negotiation timeout"); } var handshake = await handshakeTask; if (handshake.IsValid) { result = new WebSocketNegotiationResult(handshake.Factory.CreateWebSocket(stream, _options, (IPEndPoint)client.LocalEndPoint, (IPEndPoint)client.RemoteEndPoint, handshake.Request, handshake.Response, handshake.NegotiatedMessageExtensions)); } else { SafeEnd.Dispose(client); result = new WebSocketNegotiationResult(handshake.Error); } } catch (Exception ex) { SafeEnd.Dispose(client); result = new WebSocketNegotiationResult(ExceptionDispatchInfo.Capture(ex)); } try { await _negotiations.SendAsync(result, _cancel.Token).ConfigureAwait(false); } finally { _semaphore.Release(); } }
public void DoSimpleHandshakeWithEndpoints() { var handshaker = new WebSocketHandshaker(this.factories, new WebSocketListenerOptions { Logger = this.logger }); using (var connectionInput = new MemoryStream()) using (var connectionOutput = new MemoryStream()) using (var connection = new DummyNetworkConnection(connectionInput, connectionOutput)) { using (var sw = new StreamWriter(connectionInput, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Upgrade: websocket"); sw.WriteLine(@"Connection: Upgrade"); sw.WriteLine(@"Cookie: key=W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5;"); sw.WriteLine(@"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw=="); sw.WriteLine(@"Sec-WebSocket-Version: 13"); sw.WriteLine(@"Origin: http://example.com"); } connectionInput.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(connection).Result; Assert.Equal(connection.LocalEndPoint.ToString(), result.Request.LocalEndPoint.ToString()); Assert.Equal(connection.RemoteEndPoint.ToString(), result.Request.RemoteEndPoint.ToString()); } }
public void ParseMultipleCookie() { var handshaker = new WebSocketHandshaker(this.factories, new WebSocketListenerOptions { Logger = this.logger }); using (var connectionInput = new MemoryStream()) using (var connectionOutput = new MemoryStream()) using (var connection = new DummyNetworkConnection(connectionInput, connectionOutput)) { using (var sw = new StreamWriter(connectionInput, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Upgrade: websocket"); sw.WriteLine(@"Connection: Upgrade"); sw.WriteLine(@"Cookie: cookie1=uno; cookie2=dos"); sw.WriteLine(@"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw=="); sw.WriteLine(@"Sec-WebSocket-Version: 13"); sw.WriteLine(@"Origin: http://example.com"); } connectionInput.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(connection).Result; Assert.NotNull(result); Assert.Equal(2, result.Request.Cookies.Count); } }
public void IndicateANonWebSocketConnection() { var extension = new Mock <IWebSocketMessageExtension>(); extension.Setup(x => x.Name).Returns("test-extension"); var ext = new WebSocketExtension("test-extension", new List <WebSocketExtensionOption>(new[] { new WebSocketExtensionOption("optionA") })); IWebSocketMessageExtensionContext ctx; extension.Setup(x => x.TryNegotiate(It.IsAny <WebSocketHttpRequest>(), out ext, out ctx)) .Returns(true); var factory = new WebSocketFactoryRfc6455(); factory.MessageExtensions.Add(extension.Object); var factories = new WebSocketFactoryCollection(); factories.Add(factory); var handshaker = new WebSocketHandshaker(factories, new WebSocketListenerOptions { Logger = this.logger, SubProtocols = new[] { "superchat" } }); using (var connectionInput = new MemoryStream()) using (var connectionOutput = new MemoryStream()) using (var connection = new DummyNetworkConnection(connectionInput, connectionOutput)) { using (var sw = new StreamWriter(connectionInput, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); } connectionInput.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(connection).Result; Assert.NotNull(result); Assert.False((bool)result.IsWebSocketRequest); Assert.False((bool)result.IsVersionSupported); connectionOutput.Seek(0, SeekOrigin.Begin); var sb = new StringBuilder(); sb.AppendLine(@"HTTP/1.1 400 Bad Request"); sb.AppendLine(@"Connection: close"); sb.AppendLine(); using (var sr = new StreamReader(connectionOutput)) { var s = sr.ReadToEnd(); Assert.Equal(sb.ToString(), s); } } }
public void WebSocketHandshaker_CanUnderstandEncodedCookies() { WebSocketHandshaker handshaker = new WebSocketHandshaker(_factories, new WebSocketListenerOptions() { }); using (var ms = new MemoryStream()) { using (var sw = new StreamWriter(ms, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Upgrade: websocket"); sw.WriteLine(@"Connection: Upgrade"); sw.WriteLine(@"Cookie: key=This%20is%20encoded."); sw.WriteLine(@"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw=="); sw.WriteLine(@"Sec-WebSocket-Version: 13"); sw.WriteLine(@"Origin: http://example.com"); } var position = ms.Position; ms.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(ms).Result; Assert.IsNotNull(result); Assert.IsTrue(result.IsValid); Assert.AreEqual(1, result.Request.Cookies.Count); Assert.AreEqual("This is encoded.", result.Request.Cookies[0].Value); } }
public void WebSocketHandshaker_FailsWhenBadExtensionRequest() { var extension = new Mock <IWebSocketMessageExtension>(); extension.Setup(x => x.Name).Returns("test-extension"); WebSocketExtension ext = new WebSocketExtension("test-extension", new List <WebSocketExtensionOption>(new[] { new WebSocketExtensionOption() { ClientAvailableOption = false, Name = "optionA" } })); IWebSocketMessageExtensionContext ctx; extension.Setup(x => x.TryNegotiate(It.IsAny <WebSocketHttpRequest>(), out ext, out ctx)) .Returns(true); var config = new WebSocketListenerConfig(new WebSocketListenerOptions() { SubProtocols = new[] { "superchat" } }); config.Standards.RegisterStandard(new WebSocketFactoryRfc6455()); config.MessageExtensions.RegisterExtension(extension.Object); var handshaker = new WebSocketHandshaker(config); using (var ms = new MemoryStream()) { using (var sw = new StreamWriter(ms, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Upgrade: websocket"); sw.WriteLine(@"Connection: Upgrade"); sw.WriteLine(@"Cookie: key=W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5;"); sw.WriteLine(@"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw=="); sw.WriteLine(@"Sec-WebSocket-Protocol: chat, superchat"); sw.WriteLine(@"Sec-WebSocket-Extensions: test-extension;;Dsf,,optionA"); sw.WriteLine(@"Sec-WebSocket-Version: 13"); sw.WriteLine(@"Origin: http://example.com"); } var position = ms.Position; ms.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(ms).Result; Assert.IsTrue(result.IsWebSocketRequest); Assert.IsTrue(result.IsVersionSupported); Assert.IsTrue(result.NegotiatedMessageExtensions.Count() == 0); ms.Seek(position, SeekOrigin.Begin); StringBuilder sb = new StringBuilder(); sb.AppendLine(@"HTTP/1.1 400 Bad Request"); sb.AppendLine(); using (var sr = new StreamReader(ms)) { var s = sr.ReadToEnd(); Assert.AreEqual(sb.ToString(), s); } } }
WebSocketHandshake GenerateSimpleHandshake() { var config = new WebSocketListenerConfig(new WebSocketListenerOptions()); config.Standards.RegisterStandard(new WebSocketFactoryRfc6455()); WebSocketHandshaker handshaker = new WebSocketHandshaker(config); using (var ms = new MemoryStream()) { using (var sw = new StreamWriter(ms, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Upgrade: websocket"); sw.WriteLine(@"Connection: Upgrade"); sw.WriteLine(@"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw=="); sw.WriteLine(@"Sec-WebSocket-Version: 13"); sw.WriteLine(@"Origin: http://example.com"); } ms.Seek(0, SeekOrigin.Begin); return(handshaker.HandshakeAsync(ms).Result); } }
public void WebSocketHandshaker_CanDoSimpleHandshake_with_Endpoints() { WebSocketHandshaker handshaker = new WebSocketHandshaker(_factories, new WebSocketListenerOptions()); using (var ms = new MemoryStream()) { using (var sw = new StreamWriter(ms, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Upgrade: websocket"); sw.WriteLine(@"Connection: Upgrade"); sw.WriteLine(@"Cookie: key=W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5;"); sw.WriteLine(@"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw=="); sw.WriteLine(@"Sec-WebSocket-Version: 13"); sw.WriteLine(@"Origin: http://example.com"); } var position = ms.Position; ms.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(ms, new IPEndPoint(IPAddress.Parse("10.0.0.1"), 8888), new IPEndPoint(IPAddress.Parse("192.168.0.2"), 9999)).Result; Assert.AreEqual("10.0.0.1", result.Request.LocalEndpoint.Address.ToString()); Assert.AreEqual(8888, result.Request.LocalEndpoint.Port); Assert.AreEqual("192.168.0.2", result.Request.RemoteEndpoint.Address.ToString()); Assert.AreEqual(9999, result.Request.RemoteEndpoint.Port); } }
public void SimpleHandshakeIgnoringFallback() { var options = new WebSocketListenerOptions { Logger = this.logger }; options.HttpFallback = this.fallback.Object; var handshaker = new WebSocketHandshaker(this.factories, options); using (var connectionInput = new MemoryStream()) using (var connectionOutput = new MemoryStream()) using (var connection = new DummyNetworkConnection(connectionInput, connectionOutput)) { using (var sw = new StreamWriter(connectionInput, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Upgrade: websocket"); sw.WriteLine(@"Connection: Upgrade"); sw.WriteLine(@"Cookie: key=W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5;"); sw.WriteLine(@"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw=="); sw.WriteLine(@"Sec-WebSocket-Version: 13"); sw.WriteLine(@"Origin: http://example.com"); } connectionInput.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(connection).Result; Assert.NotNull(result); Assert.True((bool)result.IsWebSocketRequest); Assert.True((bool)result.IsVersionSupported); Assert.Equal(new Uri("http://example.com"), new Uri(result.Request.Headers[RequestHeader.Origin])); Assert.Equal((string)"server.example.com", (string)result.Request.Headers[RequestHeader.Host]); Assert.Equal((string)@"/chat", (string)result.Request.RequestUri.ToString()); Assert.Equal(1, result.Request.Cookies.Count); var cookie = result.Request.Cookies["key"]; Assert.Equal((string)"key", (string)cookie.Name); Assert.Equal((string)@"W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5", (string)cookie.Value); Assert.NotNull(result.Request.LocalEndPoint); Assert.NotNull(result.Request.RemoteEndPoint); connectionOutput.Seek(0, SeekOrigin.Begin); var sb = new StringBuilder(); sb.AppendLine(@"HTTP/1.1 101 Switching Protocols"); sb.AppendLine(@"Upgrade: websocket"); sb.AppendLine(@"Connection: Upgrade"); sb.AppendLine(@"Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk="); sb.AppendLine(); using (var sr = new StreamReader(connectionOutput)) { var s = sr.ReadToEnd(); Assert.Equal(sb.ToString(), s); } } }
public void WebSocketHandshaker_CanDoSimpleHandshakeIgnoringFallback() { var options = new WebSocketListenerOptions(); options.HttpFallback = _fallback.Object; WebSocketHandshaker handshaker = new WebSocketHandshaker(_factories, options); using (var ms = new MemoryStream()) { using (var sw = new StreamWriter(ms, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Upgrade: websocket"); sw.WriteLine(@"Connection: Upgrade"); sw.WriteLine(@"Cookie: key=W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5;"); sw.WriteLine(@"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw=="); sw.WriteLine(@"Sec-WebSocket-Version: 13"); sw.WriteLine(@"Origin: http://example.com"); } var position = ms.Position; ms.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(ms).Result; Assert.IsNotNull(result); Assert.IsTrue(result.IsWebSocketRequest); Assert.IsTrue(result.IsVersionSupported); Assert.AreEqual(new Uri("http://example.com"), result.Request.Headers.Origin); Assert.AreEqual("server.example.com", result.Request.Headers[HttpRequestHeader.Host]); Assert.AreEqual(@"/chat", result.Request.RequestUri.ToString()); Assert.AreEqual(1, result.Request.Cookies.Count); var cookie = result.Request.Cookies["key"]; Assert.AreEqual("key", cookie.Name); Assert.AreEqual(@"W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5", cookie.Value); Assert.IsNotNull(result.Request.LocalEndpoint); Assert.IsNotNull(result.Request.RemoteEndpoint); ms.Seek(position, SeekOrigin.Begin); StringBuilder sb = new StringBuilder(); sb.AppendLine(@"HTTP/1.1 101 Switching Protocols"); sb.AppendLine(@"Upgrade: websocket"); sb.AppendLine(@"Connection: Upgrade"); sb.AppendLine(@"Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk="); sb.AppendLine(); using (var sr = new StreamReader(ms)) { var s = sr.ReadToEnd(); Assert.AreEqual(sb.ToString(), s); } } }
public void DoesNotFailWhenSubProtocolRequestedButNoMatch() { var handshaker = new WebSocketHandshaker(this.factories, new WebSocketListenerOptions { Logger = this.logger, SubProtocols = new[] { "superchat2", "text" } }); using (var connectionInput = new MemoryStream()) using (var connectionOutput = new MemoryStream()) using (var connection = new DummyNetworkConnection(connectionInput, connectionOutput)) { using (var sw = new StreamWriter(connectionInput, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Upgrade: websocket"); sw.WriteLine(@"Connection: Upgrade"); sw.WriteLine(@"Cookie: key=W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5;"); sw.WriteLine(@"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw=="); sw.WriteLine(@"Sec-WebSocket-Protocol: chat, superchat"); sw.WriteLine(@"Sec-WebSocket-Version: 13"); sw.WriteLine(@"Origin: http://example.com"); } connectionInput.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(connection).Result; Assert.NotNull(result); Assert.True((bool)result.IsWebSocketRequest); Assert.True((bool)result.IsVersionSupported); Assert.Null(result.Error); Assert.True((bool)result.IsValidWebSocketRequest); Assert.True(string.IsNullOrEmpty(result.Response.Headers[ResponseHeader.WebSocketProtocol])); connectionOutput.Seek(0, SeekOrigin.Begin); var sb = new StringBuilder(); sb.AppendLine(@"HTTP/1.1 101 Switching Protocols"); sb.AppendLine(@"Upgrade: websocket"); sb.AppendLine(@"Connection: Upgrade"); sb.AppendLine(@"Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk="); sb.AppendLine(); using (var sr = new StreamReader(connectionOutput)) { var s = sr.ReadToEnd(); Assert.Equal(sb.ToString(), s); } } }
public void WebSocketHandshaker_CanReturnCookies() { var config = new WebSocketListenerConfig(new WebSocketListenerOptions() { OnHttpNegotiation = async(request, response) => { response.Cookies.Add(new System.Net.Cookie("name1", "value1")); response.Cookies.Add(new System.Net.Cookie("name2", "value2")); } }); config.Standards.RegisterStandard(new WebSocketFactoryRfc6455()); var handshaker = new WebSocketHandshaker(config); using (var ms = new MemoryStream()) { using (var sw = new StreamWriter(ms, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Upgrade: websocket"); sw.WriteLine(@"Connection: Upgrade"); sw.WriteLine(@"Cookie: key=W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5;"); sw.WriteLine(@"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw=="); sw.WriteLine(@"Sec-WebSocket-Version: 13"); sw.WriteLine(@"Origin: http://example.com"); } var position = ms.Position; ms.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(ms).Result; Assert.IsNotNull(result); ms.Seek(position, SeekOrigin.Begin); StringBuilder sb = new StringBuilder(); sb.AppendLine(@"HTTP/1.1 101 Switching Protocols"); sb.AppendLine(@"Upgrade: websocket"); sb.AppendLine(@"Connection: Upgrade"); sb.AppendLine(@"Set-Cookie: name1=value1"); sb.AppendLine(@"Set-Cookie: name2=value2"); sb.AppendLine(@"Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk="); sb.AppendLine(); using (var sr = new StreamReader(ms)) { var s = sr.ReadToEnd(); Assert.AreEqual(sb.ToString(), s); } } }
public void ReturnCookies() { var handshaker = new WebSocketHandshaker(this.factories, new WebSocketListenerOptions { Logger = this.logger, HttpAuthenticationHandler = async(request, response) => { response.Cookies.Add(new Cookie("name1", "value1")); response.Cookies.Add(new Cookie("name2", "value2")); return(true); } }); using (var connectionInput = new MemoryStream()) using (var connectionOutput = new MemoryStream()) using (var connection = new DummyNetworkConnection(connectionInput, connectionOutput)) { using (var sw = new StreamWriter(connectionInput, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Upgrade: websocket"); sw.WriteLine(@"Connection: Upgrade"); sw.WriteLine(@"Cookie: key=W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5;"); sw.WriteLine(@"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw=="); sw.WriteLine(@"Sec-WebSocket-Version: 13"); sw.WriteLine(@"Origin: http://example.com"); } connectionInput.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(connection).Result; Assert.NotNull(result); connectionOutput.Seek(0, SeekOrigin.Begin); var sb = new StringBuilder(); sb.AppendLine(@"HTTP/1.1 101 Switching Protocols"); sb.AppendLine(@"Upgrade: websocket"); sb.AppendLine(@"Connection: Upgrade"); sb.AppendLine(@"Set-Cookie: name1=value1"); sb.AppendLine(@"Set-Cookie: name2=value2"); sb.AppendLine(@"Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk="); sb.AppendLine(); using (var sr = new StreamReader(connectionOutput)) { var s = sr.ReadToEnd(); Assert.Equal(sb.ToString(), s); } } }
public void WebSocketHandshaker_CanIndicateANonWebSocketConnection() { var extension = new Mock <IWebSocketMessageExtension>(); extension.Setup(x => x.Name).Returns("test-extension"); WebSocketExtension ext = new WebSocketExtension("test-extension", new List <WebSocketExtensionOption>(new[] { new WebSocketExtensionOption() { ClientAvailableOption = false, Name = "optionA" } })); IWebSocketMessageExtensionContext ctx; extension.Setup(x => x.TryNegotiate(It.IsAny <WebSocketHttpRequest>(), out ext, out ctx)) .Returns(true); var factory = new WebSocketFactoryRfc6455(); factory.MessageExtensions.RegisterExtension(extension.Object); var factories = new WebSocketFactoryCollection(); factories.RegisterStandard(factory); WebSocketHandshaker handshaker = new WebSocketHandshaker(factories, new WebSocketListenerOptions() { SubProtocols = new[] { "superchat" } }); using (var ms = new MemoryStream()) { using (var sw = new StreamWriter(ms, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); } var position = ms.Position; ms.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(ms).Result; Assert.IsNotNull(result); Assert.IsFalse(result.IsWebSocketRequest); Assert.IsFalse(result.IsVersionSupported); ms.Seek(position, SeekOrigin.Begin); StringBuilder sb = new StringBuilder(); sb.AppendLine(@"HTTP/1.1 400 Bad Request"); sb.AppendLine(); using (var sr = new StreamReader(ms)) { var s = sr.ReadToEnd(); Assert.AreEqual(sb.ToString(), s); } } }
public void WebSocketHandshaker_DoesNotFailWhenSubProtocolRequestedButNoMatch() { var config = new WebSocketListenerConfig(new WebSocketListenerOptions() { SubProtocols = new[] { "superchatx" } }); config.Standards.RegisterStandard(new WebSocketFactoryRfc6455()); var handshaker = new WebSocketHandshaker(config); using (var ms = new MemoryStream()) { using (var sw = new StreamWriter(ms, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Upgrade: websocket"); sw.WriteLine(@"Connection: Upgrade"); sw.WriteLine(@"Cookie: key=W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5;"); sw.WriteLine(@"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw=="); sw.WriteLine(@"Sec-WebSocket-Protocol: chat, superchat"); sw.WriteLine(@"Sec-WebSocket-Version: 13"); sw.WriteLine(@"Origin: http://example.com"); } var position = ms.Position; ms.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(ms).Result; Assert.IsNotNull(result); Assert.IsTrue(result.IsWebSocketRequest); Assert.IsTrue(result.IsVersionSupported); Assert.IsNull(result.Error); Assert.IsTrue(result.IsValid); Assert.IsNull(result.Response.WebSocketProtocol); ms.Seek(position, SeekOrigin.Begin); StringBuilder sb = new StringBuilder(); sb.AppendLine(@"HTTP/1.1 101 Switching Protocols"); sb.AppendLine(@"Upgrade: websocket"); sb.AppendLine(@"Connection: Upgrade"); sb.AppendLine(@"Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk="); sb.AppendLine(); using (var sr = new StreamReader(ms)) { var s = sr.ReadToEnd(); Assert.AreEqual(sb.ToString(), s); } } }
public void SendCustomErrorCode() { var handshaker = new WebSocketHandshaker(this.factories, new WebSocketListenerOptions { Logger = this.logger, HttpAuthenticationHandler = async(req, res) => { res.Status = HttpStatusCode.Unauthorized; return(false); } }); using (var connectionInput = new MemoryStream()) using (var connectionOutput = new MemoryStream()) using (var connection = new DummyNetworkConnection(connectionInput, connectionOutput)) { using (var sw = new StreamWriter(connectionInput, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Upgrade: websocket"); sw.WriteLine(@"Connection: Upgrade"); sw.WriteLine(@"Cookie: key=W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5;"); sw.WriteLine(@"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw=="); sw.WriteLine(@"Sec-WebSocket-Version: 13"); sw.WriteLine(@"Origin: http://example.com"); } connectionInput.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(connection).Result; Assert.NotNull(result); Assert.False((bool)result.IsValidWebSocketRequest); Assert.NotNull(result.Error); connectionOutput.Seek(0, SeekOrigin.Begin); var sb = new StringBuilder(); sb.AppendLine(@"HTTP/1.1 401 Unauthorized"); sb.AppendLine(@"Connection: close"); sb.AppendLine(); using (var sr = new StreamReader(connectionOutput)) { var s = sr.ReadToEnd(); Assert.Equal(sb.ToString(), s); } } }
private async Task <WebSocketHandshake> HandshakeAsync(Stream stream, Task timeoutTask) { var handshakeTask = _handShaker.HandshakeAsync(stream); await Task.WhenAny(timeoutTask, handshakeTask).ConfigureAwait(false); if (timeoutTask.IsCompleted) { throw new WebSocketException("Negotiation timeout"); } var handshake = await handshakeTask; return(handshake); }
public void WebSocketHandshaker_CanNegotiateAndIgnoreAnExtension() { WebSocketHandshaker handshaker = new WebSocketHandshaker(_factories, new WebSocketListenerOptions() { SubProtocols = new[] { "superchat" } }); using (var ms = new MemoryStream()) { using (var sw = new StreamWriter(ms, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Upgrade: websocket"); sw.WriteLine(@"Connection: Upgrade"); sw.WriteLine(@"Cookie: key=W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5;"); sw.WriteLine(@"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw=="); sw.WriteLine(@"Sec-WebSocket-Protocol: chat, superchat"); sw.WriteLine(@"Sec-WebSocket-Extensions: test-extension"); sw.WriteLine(@"Sec-WebSocket-Version: 13"); sw.WriteLine(@"Origin: http://example.com"); } var position = ms.Position; ms.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(ms).Result; Assert.IsNotNull(result); Assert.IsTrue(result.IsWebSocketRequest); Assert.AreEqual(new Uri("http://example.com"), result.Request.Headers.Origin); Assert.AreEqual("superchat", result.Response.WebSocketProtocol); ms.Seek(position, SeekOrigin.Begin); StringBuilder sb = new StringBuilder(); sb.AppendLine(@"HTTP/1.1 101 Switching Protocols"); sb.AppendLine(@"Upgrade: websocket"); sb.AppendLine(@"Connection: Upgrade"); sb.AppendLine(@"Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk="); sb.AppendLine(@"Sec-WebSocket-Protocol: superchat"); sb.AppendLine(); using (var sr = new StreamReader(ms)) { var s = sr.ReadToEnd(); Assert.AreEqual(sb.ToString(), s); } } }
public void WebSocketHandshaker_CanDetectReturnCookieErrors() { var config = new WebSocketListenerConfig(new WebSocketListenerOptions() { OnHttpNegotiation = (req, res) => { throw new Exception("dummy"); } }); config.Standards.RegisterStandard(new WebSocketFactoryRfc6455()); var handshaker = new WebSocketHandshaker(config); using (var ms = new MemoryStream()) { using (var sw = new StreamWriter(ms, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Upgrade: websocket"); sw.WriteLine(@"Connection: Upgrade"); sw.WriteLine(@"Cookie: key=W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5;"); sw.WriteLine(@"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw=="); sw.WriteLine(@"Sec-WebSocket-Version: 13"); sw.WriteLine(@"Origin: http://example.com"); } var position = ms.Position; ms.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(ms).Result; Assert.IsNotNull(result); Assert.IsFalse(result.IsValid); Assert.IsNotNull(result.Error); ms.Seek(position, SeekOrigin.Begin); StringBuilder sb = new StringBuilder(); sb.AppendLine(@"HTTP/1.1 500 Internal Server Error"); sb.AppendLine(); using (var sr = new StreamReader(ms)) { var s = sr.ReadToEnd(); Assert.AreEqual(sb.ToString(), s); } } }
public void WebSocketHandshaker_FailWhenSubProtocolRequestedButNoMatch() { WebSocketHandshaker handshaker = new WebSocketHandshaker(_factories, new WebSocketListenerOptions() { SubProtocols = new[] { "superchat2", "text" } }); using (var ms = new MemoryStream()) { using (var sw = new StreamWriter(ms, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Upgrade: websocket"); sw.WriteLine(@"Connection: Upgrade"); sw.WriteLine(@"Cookie: key=W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5;"); sw.WriteLine(@"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw=="); sw.WriteLine(@"Sec-WebSocket-Protocol: chat, superchat"); sw.WriteLine(@"Sec-WebSocket-Version: 13"); sw.WriteLine(@"Origin: http://example.com"); } var position = ms.Position; ms.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(ms).Result; Assert.IsNotNull(result); Assert.IsTrue(result.IsWebSocketRequest); Assert.IsTrue(result.IsVersionSupported); Assert.IsNotNull(result.Error); Assert.IsFalse(result.IsValid); ms.Seek(position, SeekOrigin.Begin); StringBuilder sb = new StringBuilder(); sb.AppendLine(@"HTTP/1.1 400 Bad Request"); sb.AppendLine(); using (var sr = new StreamReader(ms)) { var s = sr.ReadToEnd(); Assert.AreEqual(sb.ToString(), s); } } }
public void WebSocketHandshaker_CanSendCustomErrorCode() { WebSocketHandshaker handshaker = new WebSocketHandshaker(_factories, new WebSocketListenerOptions() { OnHttpNegotiation = (req, res) => { res.Status = HttpStatusCode.Unauthorized; } }); using (var ms = new MemoryStream()) { using (var sw = new StreamWriter(ms, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Upgrade: websocket"); sw.WriteLine(@"Connection: Upgrade"); sw.WriteLine(@"Cookie: key=W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5;"); sw.WriteLine(@"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw=="); sw.WriteLine(@"Sec-WebSocket-Version: 13"); sw.WriteLine(@"Origin: http://example.com"); } var position = ms.Position; ms.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(ms).Result; Assert.IsNotNull(result); Assert.IsFalse(result.IsValid); Assert.IsNull(result.Error); ms.Seek(position, SeekOrigin.Begin); StringBuilder sb = new StringBuilder(); sb.AppendLine(@"HTTP/1.1 401 Unauthorized"); sb.AppendLine(); using (var sr = new StreamReader(ms)) { var s = sr.ReadToEnd(); Assert.AreEqual(sb.ToString(), s); } } }
public void HttpFallback() { var options = new WebSocketListenerOptions { Logger = this.logger }; options.HttpFallback = this.fallback.Object; var handshaker = new WebSocketHandshaker(this.factories, options); using (var connectionInput = new MemoryStream()) using (var connectionOutput = new MemoryStream()) using (var connection = new DummyNetworkConnection(connectionInput, connectionOutput)) { using (var sw = new StreamWriter(connectionInput, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Cookie: key=W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5;"); sw.WriteLine(@"Origin: http://example.com"); } connectionInput.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(connection).Result; Assert.NotNull(result); Assert.False((bool)result.IsWebSocketRequest); Assert.False((bool)result.IsValidWebSocketRequest); Assert.True((bool)result.IsValidHttpRequest); Assert.False((bool)result.IsVersionSupported); Assert.Equal(new Uri("http://example.com"), new Uri(result.Request.Headers[RequestHeader.Origin])); Assert.Equal((string)"server.example.com", (string)result.Request.Headers[RequestHeader.Host]); Assert.Equal((string)@"/chat", (string)result.Request.RequestUri.ToString()); Assert.Equal(1, result.Request.Cookies.Count); var cookie = result.Request.Cookies["key"]; Assert.Equal((string)"key", (string)cookie.Name); Assert.Equal((string)@"W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5", (string)cookie.Value); Assert.NotNull(result.Request.LocalEndPoint); Assert.NotNull(result.Request.RemoteEndPoint); } }
public void WebSocketHandshaker_CanDoHttpFallback() { var options = new WebSocketListenerOptions(); options.HttpFallback = _fallback.Object; WebSocketHandshaker handshaker = new WebSocketHandshaker(_factories, options); using (var ms = new MemoryStream()) { using (var sw = new StreamWriter(ms, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Cookie: key=W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5;"); sw.WriteLine(@"Origin: http://example.com"); } var position = ms.Position; ms.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(ms).Result; Assert.IsNotNull(result); Assert.IsFalse(result.IsWebSocketRequest); Assert.IsFalse(result.IsValidWebSocketRequest); Assert.IsTrue(result.IsValidHttpRequest); Assert.IsFalse(result.IsVersionSupported); Assert.AreEqual(new Uri("http://example.com"), result.Request.Headers.Origin); Assert.AreEqual("server.example.com", result.Request.Headers[HttpRequestHeader.Host]); Assert.AreEqual(@"/chat", result.Request.RequestUri.ToString()); Assert.AreEqual(1, result.Request.Cookies.Count); var cookie = result.Request.Cookies["key"]; Assert.AreEqual("key", cookie.Name); Assert.AreEqual(@"W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5", cookie.Value); Assert.IsNotNull(result.Request.LocalEndpoint); Assert.IsNotNull(result.Request.RemoteEndpoint); } }
private WebSocketHandshake GenerateSimpleHandshake() { var handshaker = new WebSocketHandshaker(this.factories, this.options); using (var connectionInput = new MemoryStream()) using (var connectionOutput = new MemoryStream()) using (var connection = new DummyNetworkConnection(connectionInput, connectionOutput)) { using (var sw = new StreamWriter(connectionInput, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Upgrade: websocket"); sw.WriteLine(@"Connection: Upgrade"); sw.WriteLine(@"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw=="); sw.WriteLine(@"Sec-WebSocket-Version: 13"); sw.WriteLine(@"Origin: http://example.com"); } connectionInput.Seek(0, SeekOrigin.Begin); return(handshaker.HandshakeAsync(connection).Result); } }
private async Task NegotiateWebSocket(NetworkConnection networkConnection) { if (networkConnection == null) { throw new ArgumentNullException(nameof(networkConnection)); } await Task.Yield(); WebSocketNegotiationResult result; try { var timeoutTask = Task.Delay(_options.NegotiationTimeout); foreach (var conExt in _extensions) { var extTask = conExt.ExtendConnectionAsync(networkConnection); await Task.WhenAny(timeoutTask, extTask).ConfigureAwait(false); if (timeoutTask.IsCompleted) { #pragma warning disable 4014 extTask.IgnoreFaultOrCancellation(); // make connection exception observed #pragma warning restore 4014 throw new WebSocketException($"Negotiation timeout (Extension: {conExt.GetType().Name})"); } networkConnection = await extTask.ConfigureAwait(false); } var handshakeTask = _handShaker.HandshakeAsync(networkConnection); await Task.WhenAny(timeoutTask, handshakeTask).ConfigureAwait(false); if (timeoutTask.IsCompleted) { #pragma warning disable 4014 handshakeTask.IgnoreFaultOrCancellation(); // make connection exception observed #pragma warning restore 4014 throw new WebSocketException("Negotiation timeout"); } var handshake = await handshakeTask.ConfigureAwait(false); if (handshake.IsValidWebSocketRequest) { result = new WebSocketNegotiationResult(handshake.Factory.CreateWebSocket(networkConnection, _options, handshake.Request, handshake.Response, handshake.NegotiatedMessageExtensions)); } else if (handshake.IsValidHttpRequest && _options.HttpFallback != null) { _options.HttpFallback.Post(handshake.Request, networkConnection); return; } else { SafeEnd.Dispose(networkConnection, this.log); result = new WebSocketNegotiationResult(handshake.Error); } var webSocket = result.Result; if (_negotiations.TryEnqueue(result) == false) { SafeEnd.Dispose(webSocket); return; // too many negotiations } if (webSocket != null) { this.pingQueue?.GetSubscriptionList().Add(webSocket); } } catch (Exception negotiationError) { if (this.log.IsDebugEnabled) { this.log.Debug("An error occurred while negotiating WebSocket request.", negotiationError); } SafeEnd.Dispose(networkConnection, this.log); result = new WebSocketNegotiationResult(ExceptionDispatchInfo.Capture(negotiationError)); } finally { _semaphore.Release(); } }
public void NegotiateAnExtensionWithParameters() { var extension = new Mock <IWebSocketMessageExtension>(); extension.Setup(x => x.Name).Returns("test-extension"); var ext = new WebSocketExtension("test-extension", new List <WebSocketExtensionOption>(new[] { new WebSocketExtensionOption("optionA") })); IWebSocketMessageExtensionContext ctx; extension.Setup(x => x.TryNegotiate(It.IsAny <WebSocketHttpRequest>(), out ext, out ctx)) .Returns(true); var factory = new WebSocketFactoryRfc6455(); factory.MessageExtensions.Add(extension.Object); var factories = new WebSocketFactoryCollection(); factories.Add(factory); var handshaker = new WebSocketHandshaker(factories, new WebSocketListenerOptions { Logger = this.logger, SubProtocols = new[] { "superchat" } }); using (var connectionInput = new MemoryStream()) using (var connectionOutput = new MemoryStream()) using (var connection = new DummyNetworkConnection(connectionInput, connectionOutput)) { using (var sw = new StreamWriter(connectionInput, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Upgrade: websocket"); sw.WriteLine(@"Connection: Upgrade"); sw.WriteLine(@"Cookie: key=W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5;"); sw.WriteLine(@"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw=="); sw.WriteLine(@"Sec-WebSocket-Protocol: chat, superchat"); sw.WriteLine(@"Sec-WebSocket-Extensions: test-extension;optionA"); sw.WriteLine(@"Sec-WebSocket-Version: 13"); sw.WriteLine(@"Origin: http://example.com"); } connectionInput.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(connection).Result; Assert.NotNull(result); Assert.True((bool)result.IsWebSocketRequest); Assert.Equal(new Uri("http://example.com"), new Uri(result.Request.Headers[RequestHeader.Origin])); Assert.Equal((string)"superchat", (string)result.Response.Headers[ResponseHeader.WebSocketProtocol]); connectionOutput.Seek(0, SeekOrigin.Begin); var sb = new StringBuilder(); sb.AppendLine(@"HTTP/1.1 101 Switching Protocols"); sb.AppendLine(@"Upgrade: websocket"); sb.AppendLine(@"Connection: Upgrade"); sb.AppendLine(@"Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk="); sb.AppendLine(@"Sec-WebSocket-Protocol: superchat"); sb.AppendLine(@"Sec-WebSocket-Extensions: test-extension;optionA"); sb.AppendLine(); using (var sr = new StreamReader(connectionOutput)) { var s = sr.ReadToEnd(); Assert.Equal(sb.ToString(), s); } } }
public void WebSocketHandshaker_CanNegotiateAnExtensionWithParameters() { var extension = new Mock <IWebSocketMessageExtension>(); extension.Setup(x => x.Name).Returns("test-extension"); WebSocketExtension ext = new WebSocketExtension("test-extension", new List <WebSocketExtensionOption>(new [] { new WebSocketExtensionOption() { ClientAvailableOption = false, Name = "optionA" } })); IWebSocketMessageExtensionContext ctx; extension.Setup(x => x.TryNegotiate(It.IsAny <WebSocketHttpRequest>(), out ext, out ctx)) .Returns(true); var factory = new WebSocketFactoryRfc6455(); factory.MessageExtensions.RegisterExtension(extension.Object); var factories = new WebSocketFactoryCollection(); factories.RegisterStandard(factory); WebSocketHandshaker handshaker = new WebSocketHandshaker(factories, new WebSocketListenerOptions() { SubProtocols = new[] { "superchat" } }); using (var ms = new MemoryStream()) { using (var sw = new StreamWriter(ms, Encoding.ASCII, 1024, true)) { sw.WriteLine(@"GET /chat HTTP/1.1"); sw.WriteLine(@"Host: server.example.com"); sw.WriteLine(@"Upgrade: websocket"); sw.WriteLine(@"Connection: Upgrade"); sw.WriteLine(@"Cookie: key=W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5;"); sw.WriteLine(@"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw=="); sw.WriteLine(@"Sec-WebSocket-Protocol: chat, superchat"); sw.WriteLine(@"Sec-WebSocket-Extensions: test-extension;optionA"); sw.WriteLine(@"Sec-WebSocket-Version: 13"); sw.WriteLine(@"Origin: http://example.com"); } var position = ms.Position; ms.Seek(0, SeekOrigin.Begin); var result = handshaker.HandshakeAsync(ms).Result; Assert.IsNotNull(result); Assert.IsTrue(result.IsWebSocketRequest); Assert.AreEqual(new Uri("http://example.com"), result.Request.Headers.Origin); Assert.AreEqual("superchat", result.Response.WebSocketProtocol); ms.Seek(position, SeekOrigin.Begin); StringBuilder sb = new StringBuilder(); sb.AppendLine(@"HTTP/1.1 101 Switching Protocols"); sb.AppendLine(@"Upgrade: websocket"); sb.AppendLine(@"Connection: Upgrade"); sb.AppendLine(@"Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk="); sb.AppendLine(@"Sec-WebSocket-Protocol: superchat"); sb.AppendLine(@"Sec-WebSocket-Extensions: test-extension;optionA"); sb.AppendLine(); using (var sr = new StreamReader(ms)) { var s = sr.ReadToEnd(); Assert.AreEqual(sb.ToString(), s); } } }