Adding Upgrade support, using WebSocket middleware from sample app
This commit is contained in:
parent
5e51783087
commit
7c626431a1
|
|
@ -3,10 +3,12 @@ using Microsoft.AspNet.Server.Kestrel.Http;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Kestrel
|
namespace Kestrel
|
||||||
{
|
{
|
||||||
public class ServerRequest : IHttpRequestFeature, IHttpResponseFeature
|
public class ServerRequest : IHttpRequestFeature, IHttpResponseFeature, IHttpOpaqueUpgradeFeature
|
||||||
{
|
{
|
||||||
Frame _frame;
|
Frame _frame;
|
||||||
string _scheme;
|
string _scheme;
|
||||||
|
|
@ -172,9 +174,40 @@ namespace Kestrel
|
||||||
_frame.ResponseBody = value;
|
_frame.ResponseBody = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IHttpResponseFeature.OnSendingHeaders(Action<object> callback, object state)
|
void IHttpResponseFeature.OnSendingHeaders(Action<object> callback, object state)
|
||||||
{
|
{
|
||||||
_frame.OnSendingHeaders(callback, state);
|
_frame.OnSendingHeaders(callback, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IHttpOpaqueUpgradeFeature.IsUpgradableRequest
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
string[] values;
|
||||||
|
if (_frame.RequestHeaders.TryGetValue("Connection", out values))
|
||||||
|
{
|
||||||
|
return values.Any(value => value.IndexOf("upgrade", StringComparison.OrdinalIgnoreCase) != -1);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task<Stream> IHttpOpaqueUpgradeFeature.UpgradeAsync()
|
||||||
|
{
|
||||||
|
_frame.StatusCode = 101;
|
||||||
|
_frame.ReasonPhrase = "Switching Protocols";
|
||||||
|
_frame.ResponseHeaders["Connection"] = new string[] { "Upgrade" };
|
||||||
|
if (!_frame.ResponseHeaders.ContainsKey("Upgrade"))
|
||||||
|
{
|
||||||
|
string[] values;
|
||||||
|
if (_frame.RequestHeaders.TryGetValue("Upgrade", out values))
|
||||||
|
{
|
||||||
|
_frame.ResponseHeaders["Upgrade"] = values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_frame.ProduceStart();
|
||||||
|
return _frame.DuplexStream;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
|
|
||||||
List<KeyValuePair<Action<object>, object>> _onSendingHeaders;
|
List<KeyValuePair<Action<object>, object>> _onSendingHeaders;
|
||||||
object _onSendingHeadersSync = new Object();
|
object _onSendingHeadersSync = new Object();
|
||||||
Stream _duplexStream;
|
|
||||||
|
|
||||||
public Frame(ConnectionContext context) : base(context)
|
public Frame(ConnectionContext context) : base(context)
|
||||||
{
|
{
|
||||||
|
|
@ -87,6 +86,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
public IDictionary<string, string[]> ResponseHeaders { get; set; }
|
public IDictionary<string, string[]> ResponseHeaders { get; set; }
|
||||||
public Stream ResponseBody { get; set; }
|
public Stream ResponseBody { get; set; }
|
||||||
|
|
||||||
|
public Stream DuplexStream { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
public bool LocalIntakeFin
|
public bool LocalIntakeFin
|
||||||
|
|
@ -175,7 +177,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
_keepAlive = MessageBody.RequestKeepAlive;
|
_keepAlive = MessageBody.RequestKeepAlive;
|
||||||
RequestBody = new FrameRequestStream(MessageBody);
|
RequestBody = new FrameRequestStream(MessageBody);
|
||||||
ResponseBody = new FrameResponseStream(this);
|
ResponseBody = new FrameResponseStream(this);
|
||||||
_duplexStream = new FrameDuplexStream(RequestBody, ResponseBody);
|
DuplexStream = new FrameDuplexStream(RequestBody, ResponseBody);
|
||||||
SocketInput.Free();
|
SocketInput.Free();
|
||||||
Task.Run(ExecuteAsync);
|
Task.Run(ExecuteAsync);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
using Microsoft.AspNet.Builder;
|
using Microsoft.AspNet.Builder;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Net.WebSockets;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace SampleApp
|
namespace SampleApp
|
||||||
{
|
{
|
||||||
|
|
@ -7,6 +10,8 @@ namespace SampleApp
|
||||||
{
|
{
|
||||||
public void Configure(IBuilder app)
|
public void Configure(IBuilder app)
|
||||||
{
|
{
|
||||||
|
app.UseWebSockets();
|
||||||
|
|
||||||
app.Run(async context =>
|
app.Run(async context =>
|
||||||
{
|
{
|
||||||
Console.WriteLine("{0} {1}{2}{3}",
|
Console.WriteLine("{0} {1}{2}{3}",
|
||||||
|
|
@ -15,10 +20,44 @@ namespace SampleApp
|
||||||
context.Request.Path,
|
context.Request.Path,
|
||||||
context.Request.QueryString);
|
context.Request.QueryString);
|
||||||
|
|
||||||
context.Response.ContentLength = 11;
|
if (context.IsWebSocketRequest)
|
||||||
context.Response.ContentType = "text/plain";
|
{
|
||||||
await context.Response.WriteAsync("Hello world");
|
var webSocket = await context.AcceptWebSocketAsync();
|
||||||
|
await EchoAsync(webSocket);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Response.ContentLength = 11;
|
||||||
|
context.Response.ContentType = "text/plain";
|
||||||
|
await context.Response.WriteAsync("Hello world");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task EchoAsync(WebSocket webSocket)
|
||||||
|
{
|
||||||
|
var buffer = new ArraySegment<byte>(new byte[8192]);
|
||||||
|
for (; ;)
|
||||||
|
{
|
||||||
|
var result = await webSocket.ReceiveAsync(
|
||||||
|
buffer,
|
||||||
|
CancellationToken.None);
|
||||||
|
|
||||||
|
if (result.MessageType == WebSocketMessageType.Close)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (result.MessageType == WebSocketMessageType.Text)
|
||||||
|
{
|
||||||
|
Console.WriteLine("{0}", System.Text.Encoding.UTF8.GetString(buffer.Array, 0, result.Count));
|
||||||
|
}
|
||||||
|
|
||||||
|
await webSocket.SendAsync(
|
||||||
|
new ArraySegment<byte>(buffer.Array, 0, result.Count),
|
||||||
|
result.MessageType,
|
||||||
|
result.EndOfMessage,
|
||||||
|
CancellationToken.None);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,7 +2,8 @@
|
||||||
"version": "1.0.0-*",
|
"version": "1.0.0-*",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Kestrel": "1.0.0-*",
|
"Kestrel": "1.0.0-*",
|
||||||
"Microsoft.AspNet.Server.WebListener": "1.0.0-*"
|
"Microsoft.AspNet.Server.WebListener": "1.0.0-*",
|
||||||
|
"Microsoft.AspNet.WebSockets.Middleware": "1.0.0-*"
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"net45": { },
|
"net45": { },
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue