private async Task ReadResponseAsync(WebSocketHandshake handshake, Stream stream) { var bufferSize = this.options.BufferManager.LargeBufferSize; using (var reader = new StreamReader(stream, Encoding.ASCII, false, bufferSize, leaveOpen: true)) { var responseHeaders = handshake.Response.Headers; var responseLine = await reader.ReadLineAsync().ConfigureAwait(false) ?? string.Empty; if (HttpHelper.TryParseHttpResponse(responseLine, out handshake.Response.Status, out handshake.Response.StatusDescription) == false) { if (string.IsNullOrEmpty(responseLine)) { throw new WebSocketException("Empty response. Probably connection is closed by remote party."); } else { throw new WebSocketException($"Invalid handshake response: {responseLine}."); } } if (handshake.Response.Status != HttpStatusCode.SwitchingProtocols) { throw new WebSocketException($"Invalid handshake response: {responseLine}."); } var headerLine = await reader.ReadLineAsync().ConfigureAwait(false); while (string.IsNullOrEmpty(headerLine) == false) { responseHeaders.TryParseAndAdd(headerLine); headerLine = await reader.ReadLineAsync().ConfigureAwait(false); } handshake.Response.ThrowIfInvalid(handshake.ComputeHandshake()); } ParseWebSocketExtensions(handshake); SelectExtensions(handshake); }
private void SendNegotiationResponse(WebSocketHandshake handshake, StreamWriter writer) { writer.Write("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\n"); if (handshake.Response.Cookies.Count > 0) { foreach (var cookie in handshake.Response.Cookies) { writer.Write("Set-Cookie: "); writer.Write(cookie.ToString()); writer.Write("\r\n"); } } writer.Write("Sec-WebSocket-Accept: "); writer.Write(handshake.ComputeHandshake()); // https://tools.ietf.org/html/rfc6455#section-4.2.2 /* * Sec-WebSocket-Protocol * If the client's handshake did not contain such a header field or if * the server does not agree to any of the client's requested * subprotocols, the only acceptable value is null. The absence * of such a field is equivalent to the null value (meaning that * if the server does not wish to agree to one of the suggested * subprotocols, it MUST NOT send back a |Sec-WebSocket-Protocol| * header field in its response). */ if (handshake.Response.Headers.Contains(ResponseHeader.WebSocketProtocol)) { writer.Write("\r\nSec-WebSocket-Protocol: "); writer.Write(handshake.Response.Headers[ResponseHeader.WebSocketProtocol]); } WriteHandshakeCookies(handshake, writer); writer.Write("\r\n\r\n"); }