/// <summary> /// 加载 HTTP 调用[TRY] /// </summary> /// <typeparam name="callType"></typeparam> /// <param name="socket">HTTP套接字接口</param> /// <param name="call">HTTP 调用</param> /// <param name="callInfo">HTTP 调用函数信息</param> protected void loadAsynchronous <callType>(Http.SocketBase socket, callType call, AutoCSer.WebView.CallMethodInfo callInfo) where callType : AutoCSer.WebView.CallAsynchronous <callType> { Http.Header header = socket.HttpHeader; if (header.ContentLength <= callInfo.MaxPostDataSize && (header.Method == Http.MethodType.POST || !callInfo.IsOnlyPost)) { call.LoadHeader(this, socket, call, callInfo); if (header.Method == Http.MethodType.POST && header.ContentLength != 0) { socket.GetForm(call, Http.GetFormType.CallAsynchronous); return; } long socketIdentity = socket.Identity; if (this.call(call)) { return; } call.PushPool(); socket.ResponseError(socketIdentity, Http.ResponseState.ServerError500); } else { AutoCSer.WebView.CallAsynchronous <callType> .PushNotNull(call); socket.ResponseErrorIdentity(Http.ResponseState.ServerError500); } }
/// <summary> /// 加载web调用 /// </summary> /// <param name="socket">HTTP套接字接口</param> /// <param name="call">web调用</param> /// <param name="callInfo">HTTP 调用函数信息</param> protected void load(Http.SocketBase socket, AutoCSer.WebView.Call call, AutoCSer.WebView.CallMethodInfo callInfo) { Http.Header header = socket.HttpHeader; if (header.ContentLength <= callInfo.MaxPostDataSize && (header.Method == Http.MethodType.POST || !callInfo.IsOnlyPost)) { call.LoadHeader(this, socket, callInfo); if (header.Method == Http.MethodType.POST && header.ContentLength != 0) { socket.GetForm(call, Http.GetFormType.Call); return; } long socketIdentity = socket.Identity; if (this.callSynchronize(call)) { return; } socket.ResponseError(socketIdentity, Http.ResponseState.ServerError500); } else { socket.ResponseErrorIdentity(Http.ResponseState.ServerError500); } }
/// <summary> /// HTTP文件请求处理 /// </summary> /// <param name="header">请求头部信息</param> /// <param name="fileCache">文件输出信息</param> /// <param name="response">HTTP响应</param> protected unsafe void file(Http.Header header, FileCache fileCache, ref Http.Response response) { Http.HeaderFlag headerFlag = header.Flag; if (fileCache == null) { if (response != null) { if (response.Type == Http.ResponseType.File) { if ((headerFlag & Http.HeaderFlag.IsRange) != 0 && !header.FormatRange(response.BodySize)) { response = Http.Response.RangeNotSatisfiable416; return; } if ((headerFlag & Http.HeaderFlag.IsVersion) != 0 || isStaticFileCacheControl(header.Path)) { response.CacheControl = AutoCSer.Net.Http.Response.StaticFileCacheControl; } } if ((response.Flag & Http.ResponseFlag.IsPool) != 0 && (headerFlag & Http.HeaderFlag.IsSetOrigin) != 0 && this.isOrigin(header.Origin, (headerFlag & Http.HeaderFlag.IsSsl) != 0)) { response.SetAccessControlAllowOrigin(header.OriginIndex); } } return; } if ((headerFlag & Http.HeaderFlag.IsRange) != 0 && !header.FormatRange(fileCache.Data.Length)) { response = Http.Response.RangeNotSatisfiable416; return; } byte[] cacheControl = (headerFlag & Http.HeaderFlag.IsVersion) != 0 || isStaticFileCacheControl(header.Path) ? AutoCSer.Net.Http.Response.StaticFileCacheControl : this.cacheControl; bool isOrigin = (headerFlag & Http.HeaderFlag.IsSetOrigin) != 0 && this.isOrigin(header.Origin, (headerFlag & Http.HeaderFlag.IsSsl) != 0), isHeader = !isOrigin && (headerFlag & Http.HeaderFlag.IsRange) == 0 && FileCacheQueue.IsFileCacheHeader; if (isHeader && (response = (headerFlag & Http.HeaderFlag.IsGZip) == 0 ? fileCache.Response : fileCache.GZipResponse) != null && response.IsCacheControl(cacheControl)) { return; } SubArray <byte> body = (headerFlag & Http.HeaderFlag.IsGZip) != 0 && (headerFlag & Http.HeaderFlag.IsRange) == 0 ? fileCache.GZipData : fileCache.Data; response = Http.Response.Get(); //response.State = Http.ResponseState.Ok200; if (isHeader && body.Start == FileCache.HttpHeaderSize) { response.SetCanHeaderSize(ref body); } else { response.SetBody(ref body); } response.CacheControl = cacheControl; response.ContentType = fileCache.ContentType; if (body.Array != fileCache.Data.Array) { response.SetContentEncoding(Http.Response.GZipEncoding); } response.SetLastModified(fileCache.LastModified); if (isOrigin) { response.SetAccessControlAllowOrigin(header.OriginIndex); } return; }
/// <summary> /// HTTP文件请求处理 /// </summary> /// <param name="header">请求头部</param> /// <param name="response">HTTP响应输出</param> /// <returns>文件缓存</returns> protected unsafe FileCache file(Http.Header header, ref Http.Response response) { SubArray <byte> path = header.Path; string cacheFileName = null; try { if (path.Length != 0 && WorkPath.Length + path.Length <= AutoCSer.IO.File.MaxFullNameLength) { byte[] contentType = null; bool isCompress = true; fixed(byte *pathFixed = path.Array) { byte *pathStart = pathFixed + path.Start, pathEnd = pathStart + path.Length; if (isFile(pathEnd, ref contentType, ref isCompress) == 0) { if (*pathStart == '/') { ++pathStart; } for (byte *formatStart = pathStart; formatStart != pathEnd; ++formatStart) { if (*formatStart == ':') { response = Http.Response.Blank; return(null); } #if !MONO if ((uint)(*formatStart - 'A') < 26) { *formatStart |= 0x20; } #endif } int cachePathLength = (int)(pathEnd - pathStart); FileCacheKey cacheKey = new FileCacheKey(pathIdentity, path.Array, (int)(pathStart - pathFixed), cachePathLength); FileCache fileCache = FileCacheQueue.Get(ref cacheKey); if (fileCache == null) { cacheFileName = StringExtension.FastAllocateString(WorkPath.Length + cachePathLength); fixed(char *nameFixed = cacheFileName) { char *write = nameFixed + WorkPath.Length; char directorySeparatorChar = Path.DirectorySeparatorChar; StringExtension.CopyNotNull(WorkPath, nameFixed); for (byte *start = pathStart; start != pathEnd; ++start) { *write++ = *start == '/' ? directorySeparatorChar : (char)*start; } } FileInfo file = new FileInfo(cacheFileName); if (file.Exists) { string fileName = file.FullName; if (fileName.Length > WorkPath.Length && WorkPath.equalCaseNotNull(fileName, WorkPath.Length)) { if (fileName.Length <= AutoCSer.IO.File.MaxFullNameLength && file.Length <= FileCacheQueue.MaxFileSize) { if (FileCacheQueue.Get(ref cacheKey, out fileCache, true) != 0) { try { fileCache.LastModified = file.LastWriteTimeUtc.UniversalNewBytes(); int extensionNameLength = (int)(pathEnd - getExtensionNameStart(pathEnd)); SubArray <byte> fileData = readCacheFile(new SubString { String = fileName, Start = fileName.Length - extensionNameLength, Length = extensionNameLength }); FileCacheQueue.Set(ref cacheKey, fileCache, fileCache.Set(ref fileData, contentType, cacheControl, isCompress)); if ((header.Flag & Http.HeaderFlag.IsSetIfModifiedSince) != 0 && header.IfModifiedSinceIndex.Length == fileCache.LastModified.Length) { if (Memory.EqualNotNull(fileCache.LastModified, pathFixed + header.Buffer.StartIndex + header.IfModifiedSinceIndex.StartIndex, header.IfModifiedSinceIndex.Length)) { response = Http.Response.NotChanged304; return(null); } } } finally { if (fileCache.IsData == 0) { fileCache.PulseAll(); fileCache = null; FileCacheQueue.RemoveOnly(ref cacheKey); } } } } else { if ((header.Flag & Http.HeaderFlag.IsSetIfModifiedSince) != 0 && header.IfModifiedSinceIndex.Length == Date.ToByteLength && Date.UniversalByteEquals(file.LastWriteTimeUtc, header.IfModifiedSince) == 0) { response = Http.Response.NotChanged304; return(null); } response = Http.Response.Get(); //response.State = Http.ResponseState.Ok200; response.SetBodyFile(file); response.CacheControl = cacheControl; response.ContentType = contentType; response.SetLastModified(file.LastWriteTimeUtc.UniversalNewBytes()); return(null); } } } } return(fileCache); } } } } catch (Exception error) { RegisterServer.TcpServer.Log.Add(AutoCSer.Log.LogType.Error, error, cacheFileName); } return(null); }
protected Http.Response file(Http.Header header) { Http.Response response = null; file(header, file(header, ref response), ref response); return(response); }
/// <summary> /// HTTP请求处理[TRY] /// </summary> /// <param name="socket">HTTP套接字</param> public override unsafe void Request(Http.SocketBase socket) { Http.Header header = socket.HttpHeader; SubArray <byte> path = header.Path; int index; if (header.IsSearchEngine == 0) { byte[] rewritePath; #if !MONO if (WebConfigIgnoreCase) { if ((index = callSearcher.SearchLower(ref path)) >= 0) { call(index, socket); return; } rewritePath = rewritePaths.GetLower(ref path); } else #endif { if ((index = callSearcher.Search(ref path)) >= 0) { call(index, socket); return; } rewritePath = rewritePaths.Get(ref path); } if (rewritePath != null) { Http.Response response = null; file(header, file(rewritePath, (header.Flag & Http.HeaderFlag.IsSetIfModifiedSince) == 0 ? new SubArray <byte>() : header.IfModifiedSince, ref response, false), ref response); if (response != null) { socket.ResponseIdentity(ref response); return; } socket.ResponseErrorIdentity(Http.ResponseState.NotFound404); } } else { #if !MONO if (WebConfigIgnoreCase) { if ((index = rewriteSearcher.SearchLower(ref path)) >= 0) { request(index, socket); return; } if ((index = viewSearcher.SearchLower(ref path)) >= 0) { request(index, socket); return; } if ((index = callSearcher.SearchLower(ref path)) >= 0) { call(index, socket); return; } } else #endif { if ((index = rewriteSearcher.Search(ref path)) >= 0) { request(index, socket); return; } if ((index = viewSearcher.Search(ref path)) >= 0) { request(index, socket); return; } if ((index = callSearcher.Search(ref path)) >= 0) { call(index, socket); return; } } } if (beforeFile(socket)) { base.Request(socket); } }
private void ConnectServer() { Task.Factory.StartNew(async () => { try { DataReader stream = new DataReader(this._socket.InputStream); // Read HTTP request line. string startLine = await this.ReadLine(stream); if (startLine == null) { throw new Exception("Cannot read HTTP request start line"); } Http.RequestLine requestLine = new Http.RequestLine(startLine); this._uri = new Uri(requestLine.RequestURI); // can be checked in // onConnect() // Read HTTP response headers Dictionary<string, string> map = new Dictionary<string, string>(); string line; while ((line = await this.ReadLine(stream)) != null && line.Length > 0) { Http.Header header = new Http.Header(line); map.Add(header.HeaderName.ToLower(), header.HeaderValue); } string value = map["sec-websocket-version"]; if (!"13".Equals(value)) throw new IOException("wrong Sec-WebSocket-Version"); string key = map["sec-websocket-key"]; if (key == null) throw new IOException("missed Sec-WebSocket-Key"); string accept = CreateAccept(key); string upgrade = map["upgrade"]; if (upgrade == null || !upgrade.Equals("websocket", StringComparison.OrdinalIgnoreCase)) throw new IOException("wrong Upgrade"); string connection = map["connection"]; if (connection == null || !connection.Equals("upgrade", StringComparison.OrdinalIgnoreCase)) throw new IOException("wrong Connection"); // Host and Origin can be checked later in onConnect() callback. this._host = map["host"]; if (this._host == null) throw new IOException("Missed 'Host' header"); this._origin = map["origin"]; if (this._origin == null) throw new IOException("Missed 'Origin' header"); // Some naive protocol selection. string protocols = map["sec-websocket-protocol"]; string selectedProtocol = null; if (protocols != null && protocols.Contains("chat")) selectedProtocol = "chat"; DataWriter writer = new DataWriter(this._socket.OutputStream); writer.WriteString("HTTP/1.1 101 Switching Protocols\r\n"); writer.WriteString("Upgrade: websocket\r\n"); writer.WriteString("Connection: Upgrade\r\n"); writer.WriteString("Sec-WebSocket-Accept: " + accept + "\r\n"); if (selectedProtocol != null) writer.WriteString("Sec-WebSocket-Protocol: " + selectedProtocol + "\r\n"); writer.WriteString("\r\n"); await writer.FlushAsync(); if (this.Opened != null) { this.Opened(this, EventArgs.Empty); } // Read & process frame for (; ; ) { FrameParser.Frame frame = await FrameParser.ReadFrame(stream); await this.ProcessIncomingFrame(frame); } } catch (IOException ex) { if (this.Closed != null) { this.Closed(this, new WebSocketClosedEventArgs(0, "EOF")); } } catch (Exception ex) { if (this.Closed != null) { this.Closed(this, new WebSocketClosedEventArgs(0, "Exception")); } } finally { this.Disconnect(); } }); }
private async Task ConnectClientInternal() { if (_socket != null) { throw new Exception("connect() is already called"); } try { int port = (_uri.Port != -1) ? _uri.Port : (_uri.Scheme.Equals("wss") ? 443 : 80); string path = (_uri.AbsolutePath != null) ? _uri.AbsolutePath : "/"; if (_uri.Query != null) { path += "?" + _uri.Query; } string originScheme = _uri.Scheme.Equals("wss") ? "https" : "http"; Uri origin = new Uri(originScheme + "://" + _uri.Host); // To fix: get Origin from extraHeaders if set there. this._socket = new InternalSocket(); await this._socket.ConnectAsync(_uri.Host, port); if (_uri.Scheme.Equals("wss")) { await this._socket.UpgradeToSslAsync(_uri.Host); } string key = WebSocketHelper.CreateClientKey(); DataWriter writer = new DataWriter(_socket.OutputStream); writer.WriteString("GET " + path + " HTTP/1.1\r\n"); writer.WriteString("Upgrade: websocket\r\n"); writer.WriteString("Connection: Upgrade\r\n"); writer.WriteString("Host: " + _uri.Host + "\r\n"); writer.WriteString("Origin: " + origin.ToString() + "\r\n"); writer.WriteString("Sec-WebSocket-Key: " + key + "\r\n"); writer.WriteString("Sec-WebSocket-Version: 13\r\n"); if (_extraRequestHeaders != null) { foreach (Http.Header header in _extraRequestHeaders) { writer.WriteString(header.ToString() + "\r\n"); } } writer.WriteString("\r\n"); await writer.StoreAsync(); //异步发送数据 writer.DetachStream(); //分离 writer.Dispose(); //结束writer DataReader reader = new DataReader(_socket.InputStream); reader.ByteOrder = ByteOrder.LittleEndian; //// Read HTTP response status line. var startLine = await ReadLine(reader); if (startLine == null) { throw new Exception("Received no reply from server."); } Http.StatusLine statusLine = new Http.StatusLine(startLine); int statusCode = statusLine.StatusCode; if (statusCode != 101) { throw new Exception("wrong HTTP response code: " + statusCode); } // Read HTTP response headers. string line; while ((line = await ReadLine(reader)) != null && line.Length > 0) { Http.Header header = new Http.Header(line); Debug.WriteLine(line); if (header.HeaderName.Equals("Sec-WebSocket-Accept", StringComparison.OrdinalIgnoreCase)) { string receivedAccept = header.HeaderValue; string shouldBeAccept = WebSocketHelper.CreateAccept(key); if (!receivedAccept.Equals(shouldBeAccept)) { throw new Exception("Wrong Sec-WebSocket-Accept: " + receivedAccept + " should be: " + shouldBeAccept); } } if (_serverResponseHeaders == null) { _serverResponseHeaders = new List <Http.Header>(); } _serverResponseHeaders.Add(header); } if (this.Opened != null) { this.Opened(this, EventArgs.Empty); } //Upgrade: websocket //Connection: Upgrade //Sec-WebSocket-Accept: 1xY289lHcEMbLpEBgOYRBBL9N9c= //Sec-WebSocket-Protocol: chat //Content-Type: application/octet-stream //Seq-Id: 667035124 // Read & process frame while (true) { FrameParser.Frame frame = await FrameParser.ReadFrame(reader); if (frame != null) { await ProcessIncomingFrame(frame); } } } catch (IOException ex) { if (this.Closed != null) { this.Closed(this, new WebSocketClosedEventArgs(0, "EOF")); } } catch (Exception ex) { if (this.Closed != null) { this.Closed(this, new WebSocketClosedEventArgs(0, ex.Message)); } } finally { Disconnect(); } }
private async Task ConnectClientInternal() { if (_socket != null) { throw new Exception("connect() is already called"); } await Task.Factory.StartNew(async () => { try { int port = (_uri.Port != -1) ? _uri.Port : (_uri.Scheme.Equals("wss") ? 443 : 80); string path = (_uri.AbsolutePath != null) ? _uri.AbsolutePath : "/"; if (_uri.Query != null) { path += "?" + _uri.Query; } string originScheme = _uri.Scheme.Equals("wss") ? "https" : "http"; Uri origin = new Uri(originScheme + "://" + _uri.Host); // To fix: get Origin from extraHeaders if set there. this._socket = new InternalSocket(); await this._socket.ConnectAsync(_uri.Host, port); if (_uri.Scheme.Equals("wss")) { await this._socket.UpgradeToSslAsync(_uri.Host); } string key = CreateSecKey(); DataWriter writer = new DataWriter(_socket.OutputStream); writer.WriteString("GET " + path + " HTTP/1.1\r\n"); writer.WriteString("Upgrade: websocket\r\n"); writer.WriteString("Connection: Upgrade\r\n"); writer.WriteString("Host: " + _uri.Host + "\r\n"); writer.WriteString("Origin: " + origin.ToString() + "\r\n"); writer.WriteString("Sec-WebSocket-Key: " + key + "\r\n"); writer.WriteString("Sec-WebSocket-Version: 13\r\n"); if (_extraRequestHeaders != null) { foreach (Http.Header header in _extraRequestHeaders) { writer.WriteString(header.ToString() + "\r\n"); } } writer.WriteString("\r\n"); await writer.StoreAsync(); //异步发送数据 writer.DetachStream(); //分离 writer.Dispose(); //结束writer DataReader reader = new DataReader(_socket.InputStream); reader.ByteOrder = ByteOrder.LittleEndian; //// Read HTTP response status line. var startLine = await ReadLine(reader); if (startLine == null) { throw new Exception("Received no reply from server."); } Http.StatusLine statusLine = new Http.StatusLine(startLine); int statusCode = statusLine.StatusCode; if (statusCode != 101) { throw new Exception("wrong HTTP response code: " + statusCode); } // Read HTTP response headers. string line; while ((line = await ReadLine(reader)) != null && line.Length > 0) { Http.Header header = new Http.Header(line); Debug.WriteLine(line); if (header.HeaderName.Equals("Sec-WebSocket-Accept", StringComparison.OrdinalIgnoreCase)) { string receivedAccept = header.HeaderValue; string shouldBeAccept = CreateAccept(key); if (!receivedAccept.Equals(shouldBeAccept)) throw new Exception("Wrong Sec-WebSocket-Accept: " + receivedAccept + " should be: " + shouldBeAccept); } if (_serverResponseHeaders == null) { _serverResponseHeaders = new List<Http.Header>(); } _serverResponseHeaders.Add(header); } if (this.Opened != null) { this.Opened(this, EventArgs.Empty); } //Upgrade: websocket //Connection: Upgrade //Sec-WebSocket-Accept: 1xY289lHcEMbLpEBgOYRBBL9N9c= //Sec-WebSocket-Protocol: chat //Content-Type: application/octet-stream //Seq-Id: 667035124 // Read & process frame while (true) { FrameParser.Frame frame = await FrameParser.ReadFrame(reader); if (frame != null) { await ProcessIncomingFrame(frame); } } } catch (IOException ex) { if (this.Closed != null) { this.Closed(this, new WebSocketClosedEventArgs(0, "EOF")); } } catch (Exception ex) { if (this.Closed != null) { this.Closed(this, new WebSocketClosedEventArgs(0, "Exception")); } } finally { Disconnect(); } }); }
/// <summary> /// HTTP请求处理[TRY] /// </summary> /// <param name="socket">HTTP套接字</param> public override unsafe void Request(Http.SocketBase socket) { Http.Header header = socket.HttpHeader; if (((uint)header.ContentLength | (uint)header.IsBoundary) == 0) { Http.Response response = Http.Response.Get(); SubBuffer.PoolBufferFull buffer = header.Buffer; byte[] domain = socket.IsSsl ? sslLocationDomain : locationDomain, bufferArray = buffer.Buffer; BufferIndex uri = header.UriIndex; int length = domain.Length + uri.Length; if (uri.Length != 0) { if (bufferArray[buffer.StartIndex + uri.StartIndex] == '/') { uri.Next(); if (uri.Length == 0) { goto END; } --length; } if (length <= header.HeaderEndIndex) { int startIndex = uri.StartIndex - domain.Length; if (startIndex >= 0) { Buffer.BlockCopy(domain, 0, bufferArray, startIndex += buffer.StartIndex, domain.Length); response.SetLocation(bufferArray, startIndex, length, locationState); } else { Buffer.BlockCopy(bufferArray, buffer.StartIndex + uri.StartIndex, bufferArray, buffer.StartIndex + domain.Length, uri.Length); Buffer.BlockCopy(domain, 0, bufferArray, buffer.StartIndex, domain.Length); response.SetLocation(bufferArray, buffer.StartIndex, length, locationState); } socket.ResponseIdentity(ref response); return; //int endIndex = uri.EndIndex; //if (header.HeaderEndIndex - endIndex - 7 >= length) //{ // fixed (byte* bufferFixed = bufferArray) // { // byte* bufferStart = bufferFixed + buffer.StartIndex, write = bufferStart + endIndex; // Memory.SimpleCopyNotNull64(domain, write, domain.Length); // Memory.SimpleCopyNotNull64(bufferStart + uri.StartIndex, write + domain.Length, uri.Length); // } // response.SetLocation(bufferArray, buffer.StartIndex + endIndex, length, locationState); // socket.Response(socketIdentity, ref response); // return; //} } } END: response.SetLocation(domain, locationState); socket.ResponseIdentity(ref response); } else { socket.ResponseErrorIdentity(Http.ResponseState.BadRequest400); } }
private void ConnectServer() { Task.Factory.StartNew(async() => { try { DataReader stream = new DataReader(this._socket.InputStream); // Read HTTP request line. string startLine = await this.ReadLine(stream); if (startLine == null) { throw new Exception("Cannot read HTTP request start line"); } Http.RequestLine requestLine = new Http.RequestLine(startLine); this._uri = new Uri(requestLine.RequestURI); // can be checked in // onConnect() // Read HTTP response headers Dictionary <string, string> map = new Dictionary <string, string>(); string line; while ((line = await this.ReadLine(stream)) != null && line.Length > 0) { Http.Header header = new Http.Header(line); map.Add(header.HeaderName.ToLower(), header.HeaderValue); } string value = map["sec-websocket-version"]; if (!"13".Equals(value)) { throw new IOException("wrong Sec-WebSocket-Version"); } string key = map["sec-websocket-key"]; if (key == null) { throw new IOException("missed Sec-WebSocket-Key"); } string accept = WebSocketHelper.CreateAccept(key); string upgrade = map["upgrade"]; if (upgrade == null || !upgrade.Equals("websocket", StringComparison.OrdinalIgnoreCase)) { throw new IOException("wrong Upgrade"); } string connection = map["connection"]; if (connection == null || !connection.Equals("upgrade", StringComparison.OrdinalIgnoreCase)) { throw new IOException("wrong Connection"); } // Host and Origin can be checked later in onConnect() callback. this._host = map["host"]; if (this._host == null) { throw new IOException("Missed 'Host' header"); } this._origin = map["origin"]; if (this._origin == null) { throw new IOException("Missed 'Origin' header"); } // Some naive protocol selection. string protocols = map["sec-websocket-protocol"]; string selectedProtocol = null; if (protocols != null && protocols.Contains("chat")) { selectedProtocol = "chat"; } DataWriter writer = new DataWriter(this._socket.OutputStream); writer.WriteString("HTTP/1.1 101 Switching Protocols\r\n"); writer.WriteString("Upgrade: websocket\r\n"); writer.WriteString("Connection: Upgrade\r\n"); writer.WriteString("Sec-WebSocket-Accept: " + accept + "\r\n"); if (selectedProtocol != null) { writer.WriteString("Sec-WebSocket-Protocol: " + selectedProtocol + "\r\n"); } writer.WriteString("\r\n"); await writer.FlushAsync(); if (this.Opened != null) { this.Opened(this, EventArgs.Empty); } // Read & process frame for (;;) { FrameParser.Frame frame = await FrameParser.ReadFrame(stream); await this.ProcessIncomingFrame(frame); } } catch (IOException ex) { if (this.Closed != null) { this.Closed(this, new WebSocketClosedEventArgs(0, "EOF")); } } catch (Exception ex) { if (this.Closed != null) { this.Closed(this, new WebSocketClosedEventArgs(0, "Exception")); } } finally { this.Disconnect(); } }); }