Negotiate sub-protocol.

This commit is contained in:
Chris Ross 2014-03-09 20:55:43 -07:00
parent 65532849f6
commit 2dbe40dca5
3 changed files with 50 additions and 6 deletions

View File

@ -10,7 +10,8 @@ namespace Microsoft.Net.WebSockets
{
public static class Headers
{
public const string WebSocketVersion = "Sec-WebSocket-Version";
public const string SecWebSocketVersion = "Sec-WebSocket-Version";
public const string SecWebSocketProtocol = "Sec-WebSocket-Protocol";
public const string SupportedVersion = "13";
}

View File

@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.WebSockets;
using System.Threading;
@ -26,6 +28,13 @@ namespace Microsoft.Net.WebSockets.Client
{
ReceiveBufferSize = 1024 * 16;
KeepAliveInterval = TimeSpan.FromMinutes(2);
SubProtocols = new List<string>();
}
public IList<string> SubProtocols
{
get;
private set;
}
public TimeSpan KeepAliveInterval
@ -64,8 +73,11 @@ namespace Microsoft.Net.WebSockets.Client
CancellationTokenRegistration cancellation = cancellationToken.Register(() => request.Abort());
request.Headers[Constants.Headers.WebSocketVersion] = Constants.Headers.SupportedVersion;
// TODO: Sub-protocols
request.Headers[Constants.Headers.SecWebSocketVersion] = Constants.Headers.SupportedVersion;
if (SubProtocols.Count > 0)
{
request.Headers[Constants.Headers.SecWebSocketProtocol] = string.Join(", ", SubProtocols);
}
if (ConfigureRequest != null)
{
@ -85,14 +97,19 @@ namespace Microsoft.Net.WebSockets.Client
if (response.StatusCode != HttpStatusCode.SwitchingProtocols)
{
response.Dispose();
throw new InvalidOperationException("Incomplete handshake");
throw new InvalidOperationException("Incomplete handshake, invalid status code: " + response.StatusCode);
}
// TODO: Validate Sec-WebSocket-Key/Sec-WebSocket-Accept
// TODO: Sub protocol
string subProtocol = response.Headers[Constants.Headers.SecWebSocketProtocol];
if (!string.IsNullOrEmpty(subProtocol) && !SubProtocols.Contains(subProtocol, StringComparer.OrdinalIgnoreCase))
{
throw new InvalidOperationException("Incomplete handshake, the server specified an unknown sub-protocol: " + subProtocol);
}
Stream stream = response.GetResponseStream();
return CommonWebSocket.CreateClientWebSocket(stream, null, KeepAliveInterval, ReceiveBufferSize, useZeroMask: UseZeroMask);
return CommonWebSocket.CreateClientWebSocket(stream, subProtocol, KeepAliveInterval, ReceiveBufferSize, useZeroMask: UseZeroMask);
}
}
}

View File

@ -35,6 +35,32 @@ namespace Microsoft.Net.WebSockets.Test
}
}
[Fact]
public async Task NegotiateSubProtocol_Success()
{
using (HttpListener listener = new HttpListener())
{
listener.Prefixes.Add(ServerAddress);
listener.Start();
Task<HttpListenerContext> serverAccept = listener.GetContextAsync();
WebSocketClient client = new WebSocketClient();
client.SubProtocols.Add("alpha");
client.SubProtocols.Add("bravo");
client.SubProtocols.Add("charlie");
Task<WebSocket> clientConnect = client.ConnectAsync(new Uri(ClientAddress), CancellationToken.None);
HttpListenerContext serverContext = await serverAccept;
Assert.True(serverContext.Request.IsWebSocketRequest);
Assert.Equal("alpha, bravo, charlie", serverContext.Request.Headers["Sec-WebSocket-Protocol"]);
HttpListenerWebSocketContext serverWebSocketContext = await serverContext.AcceptWebSocketAsync("Bravo");
WebSocket clientSocket = await clientConnect;
Assert.Equal("Bravo", clientSocket.SubProtocol);
clientSocket.Dispose();
}
}
[Fact]
public async Task SendShortData_Success()
{