Negotiate sub-protocol.
This commit is contained in:
parent
65532849f6
commit
2dbe40dca5
|
|
@ -10,7 +10,8 @@ namespace Microsoft.Net.WebSockets
|
||||||
{
|
{
|
||||||
public static class Headers
|
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";
|
public const string SupportedVersion = "13";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
@ -26,6 +28,13 @@ namespace Microsoft.Net.WebSockets.Client
|
||||||
{
|
{
|
||||||
ReceiveBufferSize = 1024 * 16;
|
ReceiveBufferSize = 1024 * 16;
|
||||||
KeepAliveInterval = TimeSpan.FromMinutes(2);
|
KeepAliveInterval = TimeSpan.FromMinutes(2);
|
||||||
|
SubProtocols = new List<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IList<string> SubProtocols
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimeSpan KeepAliveInterval
|
public TimeSpan KeepAliveInterval
|
||||||
|
|
@ -64,8 +73,11 @@ namespace Microsoft.Net.WebSockets.Client
|
||||||
|
|
||||||
CancellationTokenRegistration cancellation = cancellationToken.Register(() => request.Abort());
|
CancellationTokenRegistration cancellation = cancellationToken.Register(() => request.Abort());
|
||||||
|
|
||||||
request.Headers[Constants.Headers.WebSocketVersion] = Constants.Headers.SupportedVersion;
|
request.Headers[Constants.Headers.SecWebSocketVersion] = Constants.Headers.SupportedVersion;
|
||||||
// TODO: Sub-protocols
|
if (SubProtocols.Count > 0)
|
||||||
|
{
|
||||||
|
request.Headers[Constants.Headers.SecWebSocketProtocol] = string.Join(", ", SubProtocols);
|
||||||
|
}
|
||||||
|
|
||||||
if (ConfigureRequest != null)
|
if (ConfigureRequest != null)
|
||||||
{
|
{
|
||||||
|
|
@ -85,14 +97,19 @@ namespace Microsoft.Net.WebSockets.Client
|
||||||
if (response.StatusCode != HttpStatusCode.SwitchingProtocols)
|
if (response.StatusCode != HttpStatusCode.SwitchingProtocols)
|
||||||
{
|
{
|
||||||
response.Dispose();
|
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();
|
Stream stream = response.GetResponseStream();
|
||||||
|
|
||||||
return CommonWebSocket.CreateClientWebSocket(stream, null, KeepAliveInterval, ReceiveBufferSize, useZeroMask: UseZeroMask);
|
return CommonWebSocket.CreateClientWebSocket(stream, subProtocol, KeepAliveInterval, ReceiveBufferSize, useZeroMask: UseZeroMask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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]
|
[Fact]
|
||||||
public async Task SendShortData_Success()
|
public async Task SendShortData_Success()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue