// 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 System.Collections.Generic; using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Http.Interfaces; namespace Microsoft.AspNet.Owin { using AppFunc = Func, Task>; using WebSocketAccept = Action < IDictionary, // WebSocket Accept parameters Func // WebSocketFunc callback < IDictionary, // WebSocket environment Task // Complete > >; using WebSocketAcceptAlt = Func < IWebSocketAcceptContext, // WebSocket Accept parameters Task >; /// /// This adapts the ASP.NET WebSocket Accept flow to match the OWIN WebSocket accept flow. /// This enables OWIN based components to use WebSockets on ASP.NET servers. /// public class WebSocketAcceptAdapter { private IDictionary _env; private WebSocketAcceptAlt _accept; private AppFunc _callback; private IDictionary _options; public WebSocketAcceptAdapter(IDictionary env, WebSocketAcceptAlt accept) { _env = env; _accept = accept; } private void AcceptWebSocket(IDictionary options, AppFunc callback) { _options = options; _callback = callback; _env[OwinConstants.ResponseStatusCode] = 101; } 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) { IWebSocketAcceptContext acceptContext = null; object obj; if (adapter._options != null && adapter._options.TryGetValue(typeof(IWebSocketAcceptContext).FullName, out obj)) { acceptContext = obj as IWebSocketAcceptContext; } 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); } }; } } }