internal const int FragmentLength = 1016; // Max value is int.MaxValue - 14. #endregion #region Internal Constructors // As server internal WebSocket (HttpListenerWebSocketContext context, string protocol, Logger logger) { _context = context; _protocol = protocol; _logger = logger; _closeContext = context.Close; _secure = context.IsSecureConnection; _stream = context.Stream; init (); }
private static async Task ListenerProcessingLoopAsync() { var cancellationToken = ListenerLoopTokenSource.Token; try { while (!cancellationToken.IsCancellationRequested) { HttpListenerContext context = await Listener.GetContextAsync(); if (ServerIsRunning) { if (context.Request.IsWebSocketRequest) { // HTTP is only the initial connection; upgrade to a client-specific websocket HttpListenerWebSocketContext wsContext = null; try { wsContext = await context.AcceptWebSocketAsync(subProtocol : null); int socketId = Interlocked.Increment(ref SocketCounter); var client = new ConnectedClient(socketId, wsContext.WebSocket); Clients.TryAdd(socketId, client); Console.WriteLine($"Socket {socketId}: New connection."); _ = Task.Run(() => SocketProcessingLoopAsync(client).ConfigureAwait(false)); } catch (Exception) { // server error if upgrade from HTTP to WebSocket fails context.Response.StatusCode = 500; context.Response.StatusDescription = "WebSocket upgrade failed"; context.Response.Close(); return; } } else { if (context.Request.AcceptTypes.Contains("text/html")) { Console.WriteLine("Sending HTML to client."); ReadOnlyMemory <byte> HtmlPage = new ReadOnlyMemory <byte>(Encoding.UTF8.GetBytes(SimpleHtmlClient.HTML)); context.Response.ContentType = "text/html; charset=utf-8"; context.Response.StatusCode = 200; context.Response.StatusDescription = "OK"; context.Response.ContentLength64 = HtmlPage.Length; await context.Response.OutputStream.WriteAsync(HtmlPage, CancellationToken.None); await context.Response.OutputStream.FlushAsync(CancellationToken.None); } else { context.Response.StatusCode = 400; } context.Response.Close(); } } else { // HTTP 409 Conflict (with server's current state) context.Response.StatusCode = 409; context.Response.StatusDescription = "Server is shutting down"; context.Response.Close(); return; } } } catch (HttpListenerException ex) when(ServerIsRunning) { Program.ReportException(ex); } }
// As server internal WebSocket (HttpListenerWebSocketContext context, string protocol) { _context = context; _protocol = protocol; _closeContext = context.Close; _logger = context.Log; _secure = context.IsSecureConnection; _stream = context.Stream; _waitTime = TimeSpan.FromSeconds (1); init (); }
public async Task CloseOutputAsync_HandshakeStartedFromClient_Success(WebSocketCloseStatus status, string statusDescription, WebSocketCloseStatus expectedCloseStatus) { // [ActiveIssue("https://github.com/dotnet/corefx/issues/20392", TargetFrameworkMonikers.Netcoreapp)] string expectedStatusDescription = statusDescription; if (statusDescription == null) { expectedStatusDescription = string.Empty; } HttpListenerWebSocketContext context = await GetWebSocketContext(); await ClientConnectTask; // Close the server output. Task serverCloseTask = context.WebSocket.CloseOutputAsync(status, statusDescription, new CancellationToken()); byte[] receivedClientBytes = new byte[10]; Task <WebSocketReceiveResult> clientReceiveTask = Client.ReceiveAsync(new ArraySegment <byte>(receivedClientBytes), new CancellationToken()); await Task.WhenAll(serverCloseTask, clientReceiveTask); WebSocketReceiveResult clientResult = await clientReceiveTask; Assert.Equal(new byte[10], receivedClientBytes); Assert.Equal(expectedCloseStatus, clientResult.CloseStatus); Assert.Equal(expectedStatusDescription, clientResult.CloseStatusDescription); Assert.Equal(WebSocketMessageType.Close, clientResult.MessageType); Assert.True(clientResult.EndOfMessage); Assert.Null(context.WebSocket.CloseStatus); Assert.Null(context.WebSocket.CloseStatusDescription); Assert.Equal(WebSocketState.CloseSent, context.WebSocket.State); // Trying to send if the socket initiated a close should fail. await Assert.ThrowsAsync <WebSocketException>(() => context.WebSocket.SendAsync(new ArraySegment <byte>(new byte[10]), WebSocketMessageType.Binary, false, new CancellationToken())); // Close the client. Task clientCloseTask = Client.CloseAsync(status, statusDescription, new CancellationToken()); byte[] receivedServerBytes = new byte[10]; Task <WebSocketReceiveResult> serverReceiveTask = context.WebSocket.ReceiveAsync(new ArraySegment <byte>(receivedServerBytes), new CancellationToken()); await Task.WhenAll(clientCloseTask, serverReceiveTask); WebSocketReceiveResult serverResult = await clientReceiveTask; Assert.Equal(new byte[10], receivedServerBytes); Assert.Equal(expectedCloseStatus, serverResult.CloseStatus); Assert.Equal(expectedStatusDescription, serverResult.CloseStatusDescription); Assert.Equal(WebSocketMessageType.Close, serverResult.MessageType); Assert.True(serverResult.EndOfMessage); Assert.Equal(expectedCloseStatus, context.WebSocket.CloseStatus); Assert.Equal(statusDescription, context.WebSocket.CloseStatusDescription); Assert.Equal(WebSocketState.Closed, context.WebSocket.State); // Trying to read or write if closed should fail. await Assert.ThrowsAsync <WebSocketException>(() => context.WebSocket.ReceiveAsync(new ArraySegment <byte>(receivedServerBytes), new CancellationToken())); await Assert.ThrowsAsync <WebSocketException>(() => context.WebSocket.SendAsync(new ArraySegment <byte>(receivedServerBytes), WebSocketMessageType.Binary, false, new CancellationToken())); // Trying to close again should be a nop. await context.WebSocket.CloseAsync(WebSocketCloseStatus.Empty, null, new CancellationToken()); await context.WebSocket.CloseOutputAsync(WebSocketCloseStatus.Empty, null, new CancellationToken()); }
private async void GetContextCallback(IAsyncResult iar) { if (IsRunning) { HttpListenerContext ctx = Listener.EndGetContext(iar); Listener.BeginGetContext(GetContextCallback, null); if (ctx.Request.IsWebSocketRequest) { HttpListenerWebSocketContext wsctx = await ctx.AcceptWebSocketAsync("latipium"); ArraySegment <byte> buffer = new ArraySegment <byte>(new byte[MaxReceiveSize]); #pragma warning disable 4014 wsctx.WebSocket.ReceiveAsync(buffer, CancellationTokenSource.Token).ContinueWith(task => WebsocketRead(task, wsctx.WebSocket, buffer, null)); #pragma warning restore 4014 } else { string tmp; if ((ctx.Request.UrlReferrer != null && AuthorizedHosts.Contains(ctx.Request.UrlReferrer.Host.ToLower())) || ctx.Request.UserAgent == "Latipium Daemon (https://github.com/latipium/daemon)") { if (!string.IsNullOrWhiteSpace(tmp = ctx.Request.Headers["Origin"])) { if (AuthorizedOrigins.Contains(tmp)) { ctx.Response.AddHeader("Access-Control-Allow-Origin", tmp); } } if (!string.IsNullOrWhiteSpace(tmp = ctx.Request.Headers["Access-Control-Request-Headers"])) { ctx.Response.AddHeader("Access-Control-Allow-Headers", tmp.Split(new [] { ", ", "," }, StringSplitOptions.RemoveEmptyEntries) .Where(h => AuthorizedHeaders.Any(i => h.ToLower() == i.ToLower())) .Aggregate((a, b) => string.Concat(a, ",", b))); } if (!string.IsNullOrWhiteSpace(tmp = ctx.Request.Headers["Access-Control-Request-Method"])) { if (AuthorizedMethods.Contains(tmp.ToUpper())) { ctx.Response.AddHeader("Access-Control-Allow-Methods", tmp); } } ctx.Response.AddHeader("Access-Control-Max-Age", "600"); if (ctx.Request.HttpMethod.ToUpper() != "OPTIONS") { string request; using (TextReader reader = new StreamReader(ctx.Request.InputStream)) { request = reader.ReadToEnd(); } Guid clientId = Guid.Empty; Guid.TryParse(ctx.Request.Headers["X-Latipium-Client-Id"] ?? "", out clientId); string response = Handle(ctx.Request.Url.AbsolutePath.Replace("//", "/"), request, Clients.ContainsKey(clientId) ? Clients[clientId].Ping() : null); ctx.Response.ContentType = "application/json"; using (TextWriter writer = new StreamWriter(ctx.Response.OutputStream)) { writer.Write(response); } } } else { ctx.Response.StatusCode = 403; ctx.Response.StatusDescription = "Forbidden"; if (ctx.Request.UrlReferrer != null) { WindowsService.WriteLog(string.Format("Request with invalid referrer '{0}'", ctx.Request.UrlReferrer)); } } ctx.Response.Close(); } } }
private async ValueTask ProcessRequestAsync(HttpListenerContext context, IPrincipal principal) { if (context.Request.RawUrl.StartsWith("/favicon.ico")) { Http404(context); } if (Logger.IsEnabled(LogLevel.Trace)) { Logger.LogTrace($"[http RequestTraceIdentifier]:{context.Request.RequestTraceIdentifier.ToString()}-{context.Request.RemoteEndPoint.ToString()}"); } string sim = context.Request.QueryString.Get("sim"); string channel = context.Request.QueryString.Get("channel"); if (string.IsNullOrEmpty(sim) || string.IsNullOrEmpty(channel)) { await Http400(context); return; } int.TryParse(channel, out int channelNo); if (context.Request.IsWebSocketRequest) { HttpListenerWebSocketContext wsContext = await context.AcceptWebSocketAsync(null); var jT1078HttpContext = new JT1078HttpContext(context, wsContext, principal); jT1078HttpContext.Sim = sim; jT1078HttpContext.ChannelNo = channelNo; //todo: add session manager await wsContext.WebSocket.SendAsync(Encoding.UTF8.GetBytes("hello,jt1078"), WebSocketMessageType.Text, true, CancellationToken.None); await Task.Factory.StartNew(async(state) => { //https://www.bejson.com/httputil/websocket/ //ws://127.0.0.1:15555?token=22&sim=1221&channel=1 var websocketContext = state as JT1078HttpContext; while (websocketContext.WebSocketContext.WebSocket.State == WebSocketState.Open || websocketContext.WebSocketContext.WebSocket.State == WebSocketState.Connecting) { var buffer = ArrayPool <byte> .Shared.Rent(256); try { WebSocketReceiveResult receiveResult = await websocketContext.WebSocketContext.WebSocket.ReceiveAsync(buffer, CancellationToken.None); if (receiveResult.EndOfMessage) { if (receiveResult.Count > 0) { var data = buffer.AsSpan().Slice(0, receiveResult.Count).ToArray(); if (Logger.IsEnabled(LogLevel.Trace)) { Logger.LogTrace($"[ws receive]:{Encoding.UTF8.GetString(data)}"); } await websocketContext.WebSocketContext.WebSocket.SendAsync(data, WebSocketMessageType.Text, true, CancellationToken.None); } } } finally { ArrayPool <byte> .Shared.Return(buffer); } } if (Logger.IsEnabled(LogLevel.Trace)) { Logger.LogTrace($"[ws close]:{websocketContext}"); } //todo:session close notice await websocketContext.WebSocketContext.WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None); }, jT1078HttpContext); } else { var jT1078HttpContext = new JT1078HttpContext(context, principal); jT1078HttpContext.Sim = sim; jT1078HttpContext.ChannelNo = channelNo; //todo:add session manager //todo:set http chunk //todo:session close notice byte[] b = Encoding.UTF8.GetBytes("ack"); context.Response.StatusCode = 200; context.Response.KeepAlive = true; context.Response.ContentLength64 = b.Length; await context.Response.OutputStream.WriteAsync(b, 0, b.Length); context.Response.Close(); } }
public async Task SendAsync_InvalidMessageType_ThrowsArgumentNullException(WebSocketMessageType messageType) { HttpListenerWebSocketContext context = await GetWebSocketContext(); await AssertExtensions.ThrowsAsync <ArgumentException>("messageType", () => context.WebSocket.SendAsync(new ArraySegment <byte>(), messageType, false, new CancellationToken())); }
public JT1078HttpContext(HttpListenerContext context, HttpListenerWebSocketContext webSocketContext, IPrincipal user) { Context = context; WebSocketContext = webSocketContext; User = user; }
public ListenerWebSocketTransport(HttpListenerWebSocketContext context) : base(context.WebSocket) { this.Principal = context.User; }
public SystemHttpListenerWebSocketContext(HttpListenerWebSocketContext context) { _context = context; }
/// <summary> /// Accepts a WebSocket handshake request. /// </summary> /// <returns> /// A <see cref="HttpListenerWebSocketContext"/> that represents /// the WebSocket handshake request. /// </returns> /// <param name="protocol"> /// A <see cref="string"/> that represents the subprotocol supported on /// this WebSocket connection. /// </param> /// <exception cref="ArgumentException"> /// <para> /// <paramref name="protocol"/> is empty. /// </para> /// <para> /// -or- /// </para> /// <para> /// <paramref name="protocol"/> contains an invalid character. /// </para> /// </exception> /// <exception cref="InvalidOperationException"> /// This method has already been called. /// </exception> public HttpListenerWebSocketContext AcceptWebSocket(string protocol) { if (_websocketContext != null) throw new InvalidOperationException ("The accepting is already in progress."); if (protocol != null) { if (protocol.Length == 0) throw new ArgumentException ("An empty string.", "protocol"); if (!protocol.IsToken ()) throw new ArgumentException ("Contains an invalid character.", "protocol"); } _websocketContext = new HttpListenerWebSocketContext (this, protocol); return _websocketContext; }
public static void AcceptSocket(HttpListenerWebSocketContext c) { Task.Run(() => handleReceiving(c.WebSocket, c).ConfigureAwait(false)); }
// ------------------------------------------------------------------------------------ public async Task Spawn_Context(HttpListenerContext context, uint idx_context) { // AcceptWebSocketAsync() は、キャンセルトークンをサポートしていない // 引数: サポートされている WebSocket サブプロトコル HttpListenerWebSocketContext wsc = await context.AcceptWebSocketAsync(null); MainForm.StdOut("--- WebSocket 接続完了\r\n"); using (m_WS = wsc.WebSocket) using (WS_Buf_Pool.MemBlock mem_blk = WS_Buf_Pool.Lease_MemBlock()) { m_read_WS_buf = new Read_WS_Buf(mem_blk.m_ary_buf); m_write_WS_buf = new Write_WS_Buffer(mem_blk.m_ary_buf); try { // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< #if CREATE_TEST_LEXED_CODE // Test Lexed Code を送信する Write_WS_Buffer write_ws_buf = MainForm.ms_DBG_write_WS_buf; await m_WS.SendAsync( new ArraySegment <byte>(write_ws_buf.Get_buf(), 0, write_ws_buf.Get_idx_byte_cur()) , WebSocketMessageType.Binary, true, ms_cts_shutdown.Token); #else // まずはルートフォルダのファイル情報を送信しておく FileLister.Set_DirFileNames(m_write_WS_buf, "./"); await m_write_WS_buf.SendAsync(m_WS, ms_cts_shutdown); #endif while (true) { WebSocketReceiveResult rslt = await m_WS.ReceiveAsync( new ArraySegment <byte>(mem_blk.m_ary_buf), ms_cts_shutdown.Token); if (rslt.EndOfMessage == false) { MainForm.StdOut("--- 不正な大きさのデータを受信しました。クライアントを切断します\r\n"); break; } if (m_WS.State == WebSocketState.CloseReceived) { MainForm.StdOut("--- クライアントが接続を Close しました\r\n"); break; } m_read_WS_buf.Renew(rslt.Count); switch (m_read_WS_buf.Read_ID()) { case ID.DirFileList: { ID id = m_read_WS_buf.Read_ID(); if (id != ID.Text) { throw new Exception($"不正なパラメータを受信 DirFileList / id -> {((byte)id).ToString()}"); } FileLister.Set_DirFileNames(m_write_WS_buf, m_read_WS_buf.Get_text_cur()); await m_write_WS_buf.SendAsync(m_WS, ms_cts_shutdown); } continue; case ID.Files_inDir: { ID id = m_read_WS_buf.Read_ID(); if (id != ID.Text) { throw new Exception($"不正なパラメータを受信 Files_inDir / id -> {((byte)id).ToString()}"); } string str_path_dir = m_read_WS_buf.Get_text_cur(); id = m_read_WS_buf.Read_ID(); if (id != ID.Num_int) { throw new Exception($"不正なパラメータを受信 Files_inDir / id -> {((byte)id).ToString()}"); } int SEC_Updated_recv = m_read_WS_buf.Get_Num_int(); FileLister.OnFiles_inDir(m_write_WS_buf, str_path_dir, SEC_Updated_recv); await m_write_WS_buf.SendAsync(m_WS, ms_cts_shutdown); } continue; case ID.MD_file: { var(path_md_file, SEC_Updated, idx_byte_SEC_updated) = m_read_WS_buf.Read_Req_MD(); MainForm.StdOut($"path_md_file : {path_md_file} / SEC_Updated : {SEC_Updated.ToString()}\r\n"); // ID.MD_file -> ID_Text (path_dir) -> ID_Text (file name) は Receive時の値を流用 m_write_WS_buf.Set_idx_byte(idx_byte_SEC_updated); m_write_WS_buf.Wrt_Num_int(1000); // 1000 は試験値 Lexer.LexFile(m_write_WS_buf, path_md_file); MainForm.StdOut("--- Lexing 処理完了\r\n"); m_write_WS_buf.Simplify_Buf(); MainForm.StdOut("--- Simplify_Buf 処理完了\r\n"); await m_write_WS_buf.SendAsync(m_WS, ms_cts_shutdown); } continue; } MainForm.StdOut($"--- ReceiveAsync() : 受信バイト数 -> {rslt.Count}\r\n"); MainForm.HexDump(mem_blk.m_ary_buf, 0, 20); DBG_WS_Buffer.Show_WS_buf(MainForm.ms_RBox_stdout, mem_blk.m_ary_buf, rslt.Count); // 今は、index.md のみを解析するようにしている // string ret_str = Lexer.LexFile(m_write_WS_buf, "md_root/index.md"); // string str_recv = ms_utf16_encoding.GetString(mem_blk.m_ary_buf, 0, rslt.Count); // MainForm.StdOut(str_recv); } await m_WS.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "接続を終了します", ms_cts_shutdown.Token); } catch (OperationCanceledException) { MainForm.StdOut("--- サーバーシャットダウンのシグナルを受信しました\r\n"); } catch (WebSocketException ex) { MainForm.StdOut($"!!! 例外発を補足しました WebSoketErrorCode : {ex.WebSocketErrorCode.ToString()}\r\n"); MainForm.StdOut($" {ex.ToString()}\r\n"); } catch (Exception ex) { MainForm.StdOut($"!!! 例外を補足しました : {ex.ToString()}\r\n"); } } MdSvr.Remove_task_context(idx_context); MainForm.StdOut("--- WebSocket 切断完了\r\n"); }
static async System.Threading.Tasks.Task Main(string[] args) { Console.WriteLine("TaxcomAgent2"); HttpListener httpListener = new HttpListener(); httpListener.Prefixes.Add("http://localhost:4500/"); httpListener.Start(); Console.WriteLine("Started!"); for (; ;) { HttpListenerContext context = await httpListener.GetContextAsync(); if (context.Request.IsWebSocketRequest) { HttpListenerWebSocketContext webSocketContext = await context.AcceptWebSocketAsync(null); WebSocket socket = webSocketContext.WebSocket; while (socket.State == WebSocketState.Open) { const int maxMessageSize = 4096; byte[] receiveBuffer = new byte[maxMessageSize]; WebSocketReceiveResult receiveResult = await socket.ReceiveAsync(new ArraySegment <byte>(receiveBuffer), CancellationToken.None); if (receiveResult.MessageType == WebSocketMessageType.Close) { await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); } else if (receiveResult.MessageType == WebSocketMessageType.Binary) { await socket.CloseAsync(WebSocketCloseStatus.InvalidMessageType, "Cannot accept binary frame", CancellationToken.None); } else { int count = receiveResult.Count; while (receiveResult.EndOfMessage == false) { if (count >= maxMessageSize) { string closeMessage = string.Format("Maximum message size: {0} bytes.", maxMessageSize); await socket.CloseAsync(WebSocketCloseStatus.MessageTooBig, closeMessage, CancellationToken.None); return; } receiveResult = await socket.ReceiveAsync(new ArraySegment <byte>(receiveBuffer, count, maxMessageSize - count), CancellationToken.None); count += receiveResult.Count; } var receivedString = Encoding.UTF8.GetString(receiveBuffer, 0, count); var echoString = WebSocketHandler(receivedString); ArraySegment <byte> outputBuffer = new ArraySegment <byte>(Encoding.UTF8.GetBytes(echoString)); await socket.SendAsync(outputBuffer, WebSocketMessageType.Text, true, CancellationToken.None); } } } else { context.Response.StatusCode = 400; } } }
public SystemNetWebSocketContext(HttpListenerWebSocketContext ctx) { this.ctx = ctx; }
/// <summary> /// WSChannel /// </summary> /// <param name="webSocketContext"></param> public WSChannel(HttpListenerWebSocketContext webSocketContext) { Id = ++_id; this.webSocketContext = webSocketContext; webSocket = webSocketContext.WebSocket; }
static public async Task RunWebSocketServer() { try { while (true) { HttpListenerContext context = await s_listener.GetContextAsync().ConfigureAwait(false); if (!context.Request.IsWebSocketRequest) { context.Response.StatusCode = (int)HttpStatusCode.BadRequest; context.Response.Close(); } HttpListenerWebSocketContext webSocketContext = await context .AcceptWebSocketAsync(WebSocketConstants.SubProtocols.Amqpwsb10, 8 * 1024, s_fiveMinutes) .ConfigureAwait(false); var buffer = new byte[1 * 1024]; var arraySegment = new ArraySegment <byte>(buffer); var cancellationToken = new CancellationToken(); WebSocketReceiveResult receiveResult = await webSocketContext.WebSocket .ReceiveAsync(arraySegment, cancellationToken) .ConfigureAwait(false); // Echo the data back to the client var responseCancellationToken = new CancellationToken(); var responseBuffer = new byte[receiveResult.Count]; for (int i = 0; i < receiveResult.Count; i++) { responseBuffer[i] = arraySegment.Array[i]; } var responseSegment = new ArraySegment <byte>(responseBuffer); await webSocketContext.WebSocket .SendAsync(responseSegment, WebSocketMessageType.Binary, true, responseCancellationToken) .ConfigureAwait(false); // Have a pending read using var source = new CancellationTokenSource(s_oneMinute); WebSocketReceiveResult result = await webSocketContext.WebSocket .ReceiveAsync(arraySegment, source.Token) .ConfigureAwait(false); int bytes = result.Count; } } catch (TaskCanceledException) { return; } catch (ObjectDisposedException) { return; } catch (WebSocketException) { return; } catch (HttpListenerException) { return; } }
//------------------- // Task: when a connection is requested, depending on whether it's an HTTP request or WebSocket request, do different things. private async Task HandleConnection(Task <HttpListenerContext> listenerContext) { HttpListenerContext httpContext = listenerContext.Result; if (httpContext.Request.IsWebSocketRequest) { // Kick off an async task to upgrade the web socket and do send/recv messaging, but fail if it takes more than a second to finish. try { _logger?.Invoke("WebSocketServer.HandleConnection - websocket detected. Upgrading connection.", 1); using (CancellationTokenSource upgradeTimeout = new CancellationTokenSource(_connectionMS)) { HttpListenerWebSocketContext webSocketContext = await Task.Run(async() => { return(await httpContext.AcceptWebSocketAsync(null).ConfigureAwait(false)); }, upgradeTimeout.Token); _logger?.Invoke("WebSocketServer.HandleConnection - websocket detected. Upgraded.", 1); RGWebSocket rgws = new RGWebSocket(_onReceiveMsgText, _onReceiveMsgBinary, OnDisconnection, _logger, httpContext.Request.RemoteEndPoint.ToString(), webSocketContext.WebSocket, 25); _websockets.TryAdd(rgws._uniqueId, rgws); _websocketConnection(rgws); } } catch (OperationCanceledException) // timeout { _logger?.Invoke("WebSocketServer.HandleConnection - websocket upgrade timeout", 1); httpContext.Response.StatusCode = 500; httpContext.Response.Close(); } catch // anything else { _logger?.Invoke("WebSocketServer.HandleConnection - websocket upgrade exception", 1); httpContext.Response.StatusCode = 500; httpContext.Response.Close(); } } else // let the application specify what the HTTP response is, but we do the async write here to free up the app to do other things { try { _logger?.Invoke("WebSocketServer.HandleConnection - normal http request", 1); using (CancellationTokenSource responseTimeout = new CancellationTokenSource(_connectionMS)) { byte[] buffer = null; httpContext.Response.StatusCode = _httpRequestCallback(httpContext, out buffer); httpContext.Response.ContentLength64 = buffer.Length; await httpContext.Response.OutputStream.WriteAsync(buffer, 0, buffer.Length, responseTimeout.Token); } } catch (OperationCanceledException) // timeout { _logger?.Invoke("WebSocketServer.HandleConnection - http response timeout", 1); httpContext.Response.StatusCode = 500; } catch // anything else { _logger?.Invoke("WebSocketServer.HandleConnection - http callback handler exception", 1); httpContext.Response.StatusCode = 500; } finally { httpContext.Response.Close(); } } }
public async Task SendAsync_NoInnerBuffer_ThrowsArgumentNullException() { HttpListenerWebSocketContext context = await GetWebSocketContext(); await AssertExtensions.ThrowsAsync <ArgumentNullException>("buffer.Array", () => context.WebSocket.SendAsync(new ArraySegment <byte>(), WebSocketMessageType.Text, false, new CancellationToken())); }
private static void RunHttpListener() { _httpListener = new HttpListener(); if (!IsNullOrEmpty(_options.AdapterAddress)) { } var prefix = Format(UrlPrefix, "+", _options.ListenPort); _httpListener.Prefixes.Add(prefix + _options.UrlIdentifier + "/"); try { _httpListener.Start(); } catch (Exception ex) { PrintToConsole("Exception creating web listener: " + ex.Message); PrintToConsole("Probably the URL is not reserved - either reserve, or run as admin!"); PrintToConsole("For reference, type from elevated command prompt:"); PrintToConsole($@"netsh http add urlacl url={prefix} user=BUILTIN\users"); PrintToConsole(""); PrintToConsole("Hit any key to exit"); Console.ReadLine(); Environment.Exit((int)ExitCodes.UrlAccessDenied); } ThreadPool.QueueUserWorkItem(o => { try { while (_httpListener.IsListening) { ThreadPool.QueueUserWorkItem(c => { var ctx = c as HttpListenerContext; try { if (ctx == null) { return; } ctx.Response.ContentType = "video/mp2t"; ctx.Response.Headers.Add("Access-Control-Allow-Origin", "*"); if (ctx.Request.RemoteEndPoint == null) { return; } var streamClient = new StreamClient(_ringBuffer) { ClientAddress = ctx.Request.RemoteEndPoint.ToString() }; if (ctx.Request.IsWebSocketRequest) { HttpListenerWebSocketContext webSocketContext = ctx.AcceptWebSocketAsync(null).Result; WebSocket webSocket = webSocketContext.WebSocket; streamClient.WebSocket = webSocket; } else { streamClient.OutputWriter = new BinaryWriter(ctx.Response.OutputStream); } lock (StreamingClients) { StreamingClients.Add(streamClient); } streamClient.Start(); } catch (Exception ex) { PrintToConsole($"Exception: {ex.Message}"); } }, _httpListener.GetContext()); } } catch (Exception ex) { PrintToConsole($"Exception: {ex.Message}"); } }); }
internal WebSocket(HttpListenerWebSocketContext context) : this() { _uri = context.Path.ToUri(); _context = context; _httpContext = context.BaseContext; _wsStream = context.Stream; _endPoint = context.ServerEndPoint; _isClient = false; _isSecure = context.IsSecureConnection; }
private async Task HandleListener(CancellationToken token) { try { // TODO: Handle server cap URL HttpListenerContext context = await _httpListener.GetContextAsync(); if (token.IsCancellationRequested) { CleanUpContext(context); return; } var headers = GetWebSocketHeaders(context.Request.Headers, context.Request.QueryString); if (!context.Request.IsWebSocketRequest) { CleanUpContext(context); return; } if (!EtpWebSocketValidation.IsWebSocketRequestUpgrading(headers)) { context.Response.StatusCode = (int)HttpStatusCode.UpgradeRequired; context.Response.StatusDescription = "Invalid web socket request"; CleanUpContext(context); return; } var preferredProtocol = EtpWebSocketValidation.GetPreferredSubProtocol(headers); if (preferredProtocol == null) { context.Response.StatusCode = (int)HttpStatusCode.BadRequest; context.Response.StatusDescription = "Invalid web socket request"; CleanUpContext(context); return; } if (!EtpWebSocketValidation.IsEtpEncodingValid(headers)) { context.Response.StatusCode = (int)HttpStatusCode.PreconditionFailed; context.Response.StatusDescription = "Invalid etp-encoding header"; CleanUpContext(context); return; } HttpListenerWebSocketContext webSocketContext = await context.AcceptWebSocketAsync(preferredProtocol); if (token.IsCancellationRequested) { webSocketContext.WebSocket.Dispose(); context.Response.Close(); return; } var server = new EtpServer(webSocketContext.WebSocket, ApplicationName, ApplicationVersion, headers); server.SupportedObjects = SupportedObjects; RegisterAll(server); _servers[server.SessionId] = server; _serverTasks[server.SessionId] = Task.Run(async() => { try { InvokeSessionConnected(server); await server.HandleConnection(token); } finally { InvokeSessionClosed(server); CleanUpServer(server); webSocketContext.WebSocket.Dispose(); CleanUpContext(context); } }, token); } catch (Exception ex) { if (!ex.ExceptionMeansConnectionTerminated()) { Log("Error: Exception caught when handling a websocket connection: {0}", ex.Message); Logger.DebugFormat("Exception caught when handling a websocket connection: {0}", ex); throw; } } }
static async Task handleWebSocket(HttpListenerContext context, Authentication authentication) { User user = UserManager.Instance.GetUserFromId(authentication.UserID); HttpListenerWebSocketContext websocket = await context.AcceptWebSocketAsync(null); Action <string, bool> onWriteLine = null; onWriteLine = delegate(string line, bool dontHttpEncode) { if (websocket == null || websocket.WebSocket.State != WebSocketState.Open) { Console.WriteLine("error, websocket is not connected"); return; } if (!dontHttpEncode) { line = System.Web.HttpUtility.HtmlEncode(line); } line = line.Replace("\n", "<br>"); byte[] buffer = Encoding.UTF8.GetBytes(line); websocket.WebSocket.SendAsync(new ArraySegment <byte>(buffer), WebSocketMessageType.Text, true, System.Threading.CancellationToken.None).ConfigureAwait(true).GetAwaiter().GetResult(); }; OutputConsole.OnWriteLine += onWriteLine; OutputConsole.WriteLine(user.Username + " connected to console!"); CancellationTokenSource token = new CancellationTokenSource(); DateTime lastHeartBeat = DateTime.Now; Task.Factory.StartNew(async delegate { while (true) { if (websocket == null) { return; } byte[] heartbeatBuffer = new byte[16]; await websocket.WebSocket.ReceiveAsync(new ArraySegment <byte>(heartbeatBuffer, 0, heartbeatBuffer.Length), token.Token); lastHeartBeat = DateTime.Now; } }, token.Token); Task.Factory.StartNew(async delegate { while (true) { await Task.Delay(1000); TimeSpan time = DateTime.Now - lastHeartBeat; if (time.TotalSeconds > 3) { OutputConsole.OnWriteLine -= onWriteLine; websocket.WebSocket.Abort(); websocket.WebSocket.Dispose(); websocket = null; token.Cancel(); OutputConsole.WriteLine(user.Username + " disconnected (Connection timed out)"); return; } } }, token.Token); }
internal WebSocketData(HttpListenerWebSocketContext context, string subProtocol) { Context = context; SubProtocol = subProtocol; }
public DotNetWebSocketClient(HttpListenerContext httpContext, HttpListenerWebSocketContext webSocketContext, string guid) { this.Guid = guid; this.httpContext = httpContext; this.webSocketContext = webSocketContext; }
private async Task HandleListenerCore(CancellationToken token) { try { HttpListenerContext context = await _httpListener.GetContextAsync().ConfigureAwait(false); if (token.IsCancellationRequested) { CleanUpContext(context); return; } var headers = GetCombinedHeaders(context.Request.Headers, context.Request.QueryString); if (IsServerCapabilitiesRequest(context.Request)) { Logger.Info($"Handling ServerCapabilities request from {context.Request.RemoteEndPoint}."); HandleServerCapabilitiesRequest(context.Response, headers); CleanUpContext(context); return; } if (!context.Request.IsWebSocketRequest) { CleanUpContext(context); return; } Logger.Info($"Handling WebSocket request from {context.Request.RemoteEndPoint}."); if (!EtpWebSocketValidation.IsWebSocketRequestUpgrading(headers)) { context.Response.StatusCode = (int)HttpStatusCode.UpgradeRequired; Logger.Debug($"Invalid web socket request"); context.Response.StatusDescription = "Invalid web socket request"; CleanUpContext(context); return; } var preferredProtocol = EtpWebSocketValidation.GetPreferredSubProtocol(headers); if (preferredProtocol == null) { context.Response.StatusCode = (int)HttpStatusCode.BadRequest; context.Response.StatusDescription = "Invalid web socket request"; Logger.Debug($"Invalid web socket request"); CleanUpContext(context); return; } var encoding = EtpWebSocketValidation.GetEtpEncoding(headers); if (encoding == null) { context.Response.StatusCode = (int)HttpStatusCode.PreconditionFailed; Logger.Debug($"Error getting ETP encoding."); context.Response.StatusDescription = "Invalid etp-encoding header"; CleanUpContext(context); return; } if (!Details.IsEncodingSupported(encoding.Value)) { context.Response.StatusCode = (int)HttpStatusCode.PreconditionFailed; Logger.Debug($"Encoding not supported: {encoding.Value}"); context.Response.StatusDescription = "Unsupported etp-encoding"; CleanUpContext(context); return; } HttpListenerWebSocketContext webSocketContext = await context.AcceptWebSocketAsync(preferredProtocol).ConfigureAwait(false); if (token.IsCancellationRequested) { webSocketContext.WebSocket.Dispose(); context.Response.Close(); return; } var version = EtpWebSocketValidation.GetEtpVersion(preferredProtocol); if (!Details.IsVersionSupported(version)) { context.Response.StatusCode = (int)HttpStatusCode.PreconditionFailed; Logger.Debug($"Sub protocol not supported: {preferredProtocol}"); context.Response.StatusDescription = "Sub protocol not supported"; CleanUpContext(context); return; } var ws = new EtpServerWebSocket { WebSocket = webSocketContext.WebSocket }; var server = ServerManager.CreateServer(ws, version, encoding.Value, headers); server.Start(); } catch (Exception ex) { if (!ex.ExceptionMeansConnectionTerminated()) { ServerManager.Log("Error: Exception caught when handling a websocket connection: {0}", ex.Message); Logger.DebugFormat("Exception caught when handling a websocket connection: {0}", ex); throw; } } }
// As server internal WebSocket(HttpListenerWebSocketContext context, Logger logger) { _context = context; _logger = logger; _closeContext = context.Close; _secure = context.IsSecureConnection; _stream = context.Stream; _uri = context.Path.ToUri (); init (); }
public void Start(string url) { if (!url.EndsWith("/")) { url += "/"; } ServiceEventSource.Current.Message("Starting web socket listener on " + url); this.httpListener = new HttpListener(); this.httpListener.Prefixes.Add(url); this.httpListener.Start(); Task.Run( async() => { CancellationToken cancellationToken = this.cancellationSource.Token; // This loop continuously listens for incoming client connections // as you might normally do with a web socket server. while (true) { ServiceEventSource.Current.Message("Waiting for connection.."); cancellationToken.ThrowIfCancellationRequested(); HttpListenerContext context = await this.httpListener.GetContextAsync(); Task <Task> acceptTask = context.AcceptWebSocketAsync(null).ContinueWith( async task => { HttpListenerWebSocketContext websocketContext = task.Result; ServiceEventSource.Current.Message("Connection from " + websocketContext.Origin); using (WebSocket browserSocket = websocketContext.WebSocket) { while (true) { cancellationToken.ThrowIfCancellationRequested(); string response = await this.visualObjectBox.GetObjectsAsync(cancellationToken); byte[] buffer = Encoding.UTF8.GetBytes(response); try { await browserSocket.SendAsync( new ArraySegment <byte>(buffer, 0, buffer.Length), WebSocketMessageType.Text, true, cancellationToken); if (browserSocket.State != WebSocketState.Open) { break; } } catch (WebSocketException ex) { // If the browser quit or the socket was closed, exit this loop so we can get a new browser socket. ServiceEventSource.Current.Message(ex.InnerException != null ? ex.InnerException.Message : ex.Message); break; } // wait a bit and continue. This determines the client refresh rate. await Task.Delay(TimeSpan.FromMilliseconds(5), cancellationToken); } } ServiceEventSource.Current.Message("Client disconnected."); }, TaskContinuationOptions.OnlyOnRanToCompletion); } }, this.cancellationSource.Token); }
internal WebSocket(HttpListenerWebSocketContext context) : this() { _stream = context.Stream; _closeContext = () => context.Close (); init (context); }
private async Task <WebSocketClientTermination> AcceptAsync( HttpListenerWebSocketContext context, CapturedId capturedId, CapturedShutdownReason capturedShutdownReason, QbservableServiceOptions options, Func <IQbservableProtocol, IParameterizedQbservableProvider> providerFactory, CancellationToken cancel) { Contract.Requires(context != null); Contract.Requires(capturedId != null); Contract.Requires(capturedShutdownReason != null); Contract.Requires(options != null); Contract.Requires(providerFactory != null); ReceivingConnection(idOverride: capturedId.Value); prepareSocket(context.WebSocket); var watch = Stopwatch.StartNew(); var exceptions = new List <ExceptionDispatchInfo>(); var shutdownReason = QbservableProtocolShutdownReason.None; try { using (var stream = new WebSocketStream(context.WebSocket)) using (var protocol = await NegotiateServerAsync(capturedId.Value, stream, formatterFactory(), options, cancel).ConfigureAwait(false)) { capturedId.Value = protocol.ClientId; var provider = providerFactory(protocol); ReceivedConnection(idOverride: capturedId.Value); try { await protocol.ExecuteServerAsync(provider).ConfigureAwait(false); } catch (OperationCanceledException) { } catch (Exception ex) { exceptions.Add(ExceptionDispatchInfo.Capture(ex)); } finally { shutdownReason = protocol.ShutdownReason; } var protocolExceptions = protocol.Exceptions; if (protocolExceptions != null) { foreach (var exception in protocolExceptions) { exceptions.Add(exception); } } } } catch (OperationCanceledException) { shutdownReason = QbservableProtocolShutdownReason.ProtocolNegotiationCanceled; } catch (Exception ex) { shutdownReason = QbservableProtocolShutdownReason.ProtocolNegotiationError; exceptions.Add(ExceptionDispatchInfo.Capture(ex)); } finally { capturedShutdownReason.Value = shutdownReason; } return(new WebSocketClientTermination(Uri, context.Origin, watch.Elapsed, shutdownReason, exceptions)); }