-
Notifications
You must be signed in to change notification settings - Fork 9.8k
/
WebSocketAcceptAdapter.cs
97 lines (88 loc) · 3.52 KB
/
WebSocketAcceptAdapter.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Net.WebSockets;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Owin;
using AppFunc = Func<IDictionary<string, object>, Task>;
using WebSocketAccept =
Action
<
IDictionary<string, object>, // WebSocket Accept parameters
Func // WebSocketFunc callback
<
IDictionary<string, object>, // WebSocket environment
Task // Complete
>
>;
using WebSocketAcceptAlt =
Func
<
WebSocketAcceptContext, // WebSocket Accept parameters
Task<WebSocket>
>;
/// <summary>
/// This adapts the ASP.NET Core WebSocket Accept flow to match the OWIN WebSocket accept flow.
/// This enables OWIN based components to use WebSockets on ASP.NET Core servers.
/// </summary>
public class WebSocketAcceptAdapter
{
private readonly IDictionary<string, object> _env;
private readonly WebSocketAcceptAlt _accept;
private AppFunc _callback;
private IDictionary<string, object> _options;
/// <summary>
/// Initializes a new instance of <see cref="WebSocketAcceptAdapter"/> for an OWIN environment.
/// </summary>
/// <param name="env">The OWIN environment.</param>
/// <param name="accept">WebSocket accept delegate.</param>
public WebSocketAcceptAdapter(IDictionary<string, object> env, WebSocketAcceptAlt accept)
{
_env = env;
_accept = accept;
}
private void AcceptWebSocket(IDictionary<string, object> options, AppFunc callback)
{
_options = options;
_callback = callback;
_env[OwinConstants.ResponseStatusCode] = 101;
}
/// <summary>
/// Adapt web sockets to OWIN.
/// </summary>
/// <param name="next">The next OWIN app delegate.</param>
/// <returns>An OWIN app delegate.</returns>
public static AppFunc AdaptWebSockets(AppFunc next)
{
return async environment =>
{
object accept;
if (environment.TryGetValue(OwinConstants.WebSocket.AcceptAlt, out accept) && accept is WebSocketAcceptAlt)
{
var adapter = new WebSocketAcceptAdapter(environment, (WebSocketAcceptAlt)accept);
environment[OwinConstants.WebSocket.Accept] = new WebSocketAccept(adapter.AcceptWebSocket);
await next(environment);
if ((int)environment[OwinConstants.ResponseStatusCode] == 101 && adapter._callback != null)
{
WebSocketAcceptContext acceptContext = null;
object obj;
if (adapter._options != null && adapter._options.TryGetValue(typeof(WebSocketAcceptContext).FullName, out obj))
{
acceptContext = obj as WebSocketAcceptContext;
}
else if (adapter._options != null)
{
acceptContext = new OwinWebSocketAcceptContext(adapter._options);
}
var webSocket = await adapter._accept(acceptContext);
var webSocketAdapter = new WebSocketAdapter(webSocket, (CancellationToken)environment[OwinConstants.CallCancelled]);
await adapter._callback(webSocketAdapter.Environment);
await webSocketAdapter.CleanupAsync();
}
}
else
{
await next(environment);
}
};
}
}