Server: Expose WebSocketOptions. Make feature replacement configurable.

This commit is contained in:
Chris Ross 2014-06-30 12:50:55 -07:00
parent b24d808b58
commit df425e4796
5 changed files with 83 additions and 21 deletions

View File

@ -25,11 +25,13 @@
<SchemaVersion>2.0</SchemaVersion> <SchemaVersion>2.0</SchemaVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="WebSocketAcceptContext.cs" />
<Compile Include="WebSocketMiddleware.cs" /> <Compile Include="WebSocketMiddleware.cs" />
<Compile Include="WebSocketMiddlewareExtensions.cs" /> <Compile Include="WebSocketMiddlewareExtensions.cs" />
<Compile Include="WebSocketOptions.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="project.json" /> <Content Include="project.json" />
</ItemGroup> </ItemGroup>
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" /> <Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project> </Project>

View File

@ -0,0 +1,17 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNet.HttpFeature;
namespace Microsoft.AspNet.WebSockets.Server
{
public class WebSocketAcceptContext : IWebSocketAcceptContext
{
public string SubProtocol { get; set; }
public int? ReceiveBufferSize { get; set; }
public TimeSpan? KeepAliveInterval { get; set; }
// public ArraySegment<byte>? Buffer { get; set; } // TODO
}
}

View File

@ -15,21 +15,27 @@ namespace Microsoft.AspNet.WebSockets.Server
{ {
public class WebSocketMiddleware public class WebSocketMiddleware
{ {
private RequestDelegate _next; private readonly RequestDelegate _next;
private readonly WebSocketOptions _options;
public WebSocketMiddleware(RequestDelegate next) public WebSocketMiddleware(RequestDelegate next, WebSocketOptions options)
{ {
_next = next; _next = next;
_options = options;
// TODO: validate options.
} }
public Task Invoke(HttpContext context) public Task Invoke(HttpContext context)
{ {
// Detect if an opaque upgrade is available, and if websocket upgrade headers are present. // Detect if an opaque upgrade is available. If so, add a websocket upgrade.
// If so, add a websocket upgrade.
var upgradeFeature = context.GetFeature<IHttpOpaqueUpgradeFeature>(); var upgradeFeature = context.GetFeature<IHttpOpaqueUpgradeFeature>();
if (upgradeFeature != null) if (upgradeFeature != null)
{ {
context.SetFeature<IHttpWebSocketFeature>(new UpgradeHandshake(context, upgradeFeature)); if (_options.ReplaceFeature || context.GetFeature<IHttpWebSocketFeature>() == null)
{
context.SetFeature<IHttpWebSocketFeature>(new UpgradeHandshake(context, upgradeFeature, _options));
}
} }
return _next(context); return _next(context);
@ -37,13 +43,15 @@ namespace Microsoft.AspNet.WebSockets.Server
private class UpgradeHandshake : IHttpWebSocketFeature private class UpgradeHandshake : IHttpWebSocketFeature
{ {
private HttpContext _context; private readonly HttpContext _context;
private IHttpOpaqueUpgradeFeature _upgradeFeature; private readonly IHttpOpaqueUpgradeFeature _upgradeFeature;
private readonly WebSocketOptions _options;
public UpgradeHandshake(HttpContext context, IHttpOpaqueUpgradeFeature upgradeFeature) public UpgradeHandshake(HttpContext context, IHttpOpaqueUpgradeFeature upgradeFeature, WebSocketOptions options)
{ {
_context = context; _context = context;
_upgradeFeature = upgradeFeature; _upgradeFeature = upgradeFeature;
_options = options;
} }
public bool IsWebSocketRequest public bool IsWebSocketRequest
@ -70,7 +78,7 @@ namespace Microsoft.AspNet.WebSockets.Server
{ {
if (!IsWebSocketRequest) if (!IsWebSocketRequest)
{ {
throw new InvalidOperationException("Not a WebSocket request."); throw new InvalidOperationException("Not a WebSocket request."); // TODO: LOC
} }
string subProtocol = null; string subProtocol = null;
@ -79,8 +87,8 @@ namespace Microsoft.AspNet.WebSockets.Server
subProtocol = acceptContext.SubProtocol; subProtocol = acceptContext.SubProtocol;
} }
TimeSpan keepAliveInterval = TimeSpan.FromMinutes(2); // TODO: TimeSpan keepAliveInterval = _options.KeepAliveInterval;
int receiveBufferSize = 4 * 1024; // TODO: int receiveBufferSize = _options.ReceiveBufferSize;
var advancedAcceptContext = acceptContext as WebSocketAcceptContext; var advancedAcceptContext = acceptContext as WebSocketAcceptContext;
if (advancedAcceptContext != null) if (advancedAcceptContext != null)
{ {
@ -106,13 +114,5 @@ namespace Microsoft.AspNet.WebSockets.Server
return CommonWebSocket.CreateServerWebSocket(opaqueTransport, subProtocol, keepAliveInterval, receiveBufferSize); return CommonWebSocket.CreateServerWebSocket(opaqueTransport, subProtocol, keepAliveInterval, receiveBufferSize);
} }
} }
public class WebSocketAcceptContext : IWebSocketAcceptContext
{
public string SubProtocol { get; set; }
public int? ReceiveBufferSize { get; set; }
public TimeSpan? KeepAliveInterval { get; set; }
// public ArraySegment<byte>? Buffer { get; set; } // TODO
}
} }
} }

View File

@ -9,7 +9,12 @@ namespace Microsoft.AspNet.Builder
{ {
public static IBuilder UseWebSockets(this IBuilder builder) public static IBuilder UseWebSockets(this IBuilder builder)
{ {
return builder.Use(next => new WebSocketMiddleware(next).Invoke); return builder.UseWebSockets(new WebSocketOptions());
}
public static IBuilder UseWebSockets(this IBuilder builder, WebSocketOptions options) // TODO: [NotNull]
{
return builder.Use(next => new WebSocketMiddleware(next, options).Invoke);
} }
} }
} }

View File

@ -0,0 +1,38 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace Microsoft.AspNet.WebSockets.Server
{
/// <summary>
/// Configuration options for the WebSocketMiddleware
/// </summary>
public class WebSocketOptions
{
public WebSocketOptions()
{
KeepAliveInterval = TimeSpan.FromMinutes(2);
ReceiveBufferSize = 4 * 1024;
ReplaceFeature = false;
}
/// <summary>
/// Gets or sets the frequency at which to send Ping/Pong keep-alive control frames.
/// The default is two minutes.
/// </summary>
public TimeSpan KeepAliveInterval { get; set; }
/// <summary>
/// Gets or sets the size of the protocol buffer used to receive and parse frames.
/// The default is 4kb.
/// </summary>
public int ReceiveBufferSize { get; set; }
/// <summary>
/// Gets or sets if the middleware should replace the WebSocket implementation provided by
/// a component earlier in the stack. This is false by default.
/// </summary>
public bool ReplaceFeature { get; set; }
}
}