public void CreateResponseKey() { foreach (var key in _requestKeys) { HandshakeHelpers.CreateResponseKey(key); } }
public void IsRequestKeyValid() { foreach (var key in _requestKeys) { HandshakeHelpers.IsRequestKeyValid(key); } }
public async Task <MazeSocket> AcceptAsync() { var key = string.Join(", ", _context.Request.Headers[MazeSocketHeaders.SecWebSocketKey]); var responseHeaders = HandshakeHelpers.GenerateResponseHeaders(key); foreach (var headerPair in responseHeaders) { _context.Response.Headers[headerPair.Key] = headerPair.Value; } var stream = await _upgradeFeature.UpgradeAsync(); await Task.Delay(500); string result; using (var streamReader = new StreamReader(stream)) { result = await streamReader.ReadLineAsync(); } Debug.Print("Result Server: " + result); using (var streamWriter = new StreamWriter(stream)) { await streamWriter.WriteLineAsync("Hey other"); } return(new MazeSocket(stream, _options.KeepAliveInterval)); }
public async Task <WebSocket> AcceptAsync(GameSocketAcceptContext acceptContext) { if (!IsGameSocketRequest) { throw new InvalidOperationException("Not a WebSocket request."); // TODO: LOC } var subProtocol = acceptContext?.SubProtocol; var keepAliveInterval = _options.KeepAliveInterval; var receiveBufferSize = _options.ReceiveBufferSize; if (acceptContext is ExtendedGameSocketAcceptContext advancedAcceptContext) { if (advancedAcceptContext.ReceiveBufferSize.HasValue) { receiveBufferSize = advancedAcceptContext.ReceiveBufferSize.Value; } if (advancedAcceptContext.KeepAliveInterval.HasValue) { keepAliveInterval = advancedAcceptContext.KeepAliveInterval.Value; } } var key = string.Join(", ", _context.Request.Headers[Constants.Headers.SecGameSocketKey]); HandshakeHelpers.GenerateResponseHeaders(key, subProtocol, _context.Response.Headers); var opaqueTransport = await _upgradeFeature.UpgradeAsync(); // Sets status code to 101 return(WebSocket.CreateFromStream(opaqueTransport, isServer: true, subProtocol: subProtocol, keepAliveInterval: keepAliveInterval)); }
public static bool CheckSupportedWebSocketRequest(string method, IHeaderDictionary requestHeaders) { if (!HttpMethods.IsGet(method)) { return(false); } if (!CheckWebSocketVersion(requestHeaders)) { return(false); } var foundHeader = false; var values = requestHeaders.GetCommaSeparatedValues(HeaderNames.Upgrade); foreach (var value in values) { if (string.Equals(value, Constants.Headers.UpgradeWebSocket, StringComparison.OrdinalIgnoreCase)) { // WebSockets are long lived; so if the header values are valid we switch them out for the interned versions. if (values.Length == 1) { requestHeaders.Upgrade = Constants.Headers.UpgradeWebSocket; } foundHeader = true; break; } } if (!foundHeader) { return(false); } foundHeader = false; values = requestHeaders.GetCommaSeparatedValues(HeaderNames.Connection); foreach (var value in values) { if (string.Equals(value, HeaderNames.Upgrade, StringComparison.OrdinalIgnoreCase)) { // WebSockets are long lived; so if the header values are valid we switch them out for the interned versions. if (values.Length == 1) { requestHeaders.Connection = HeaderNames.Upgrade; } foundHeader = true; break; } } if (!foundHeader) { return(false); } return(HandshakeHelpers.IsRequestKeyValid(requestHeaders.SecWebSocketKey.ToString())); }
public void CreatesCorrectResponseKey() { // Example taken from https://tools.ietf.org/html/rfc6455#section-1.3 var key = "dGhlIHNhbXBsZSBub25jZQ=="; var expectedResponse = "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="; var response = HandshakeHelpers.CreateResponseKey(key); Assert.Equal(expectedResponse, response); }
public async Task <WebSocket> AcceptAsync(IWebSocketAcceptContext acceptContext) { if (!IsWebSocketRequest) { throw new InvalidOperationException("Not a WebSocket request."); // TODO: LOC } string subProtocol = null; if (acceptContext != null) { subProtocol = acceptContext.SubProtocol; } TimeSpan keepAliveInterval = _options.KeepAliveInterval; int receiveBufferSize = _options.ReceiveBufferSize; var advancedAcceptContext = acceptContext as WebSocketAcceptContext; if (advancedAcceptContext != null) { if (advancedAcceptContext.ReceiveBufferSize.HasValue) { receiveBufferSize = advancedAcceptContext.ReceiveBufferSize.Value; } if (advancedAcceptContext.KeepAliveInterval.HasValue) { keepAliveInterval = advancedAcceptContext.KeepAliveInterval.Value; } } string key = string.Join(", ", _context.Request.Headers[Constants.Headers.SecWebSocketKey]); var responseHeaders = HandshakeHelpers.GenerateResponseHeaders(key, subProtocol); foreach (var headerPair in responseHeaders) { _context.Response.Headers[headerPair.Key] = headerPair.Value; } Stream opaqueTransport = await _upgradeFeature.UpgradeAsync(); // Sets status code to 101 return(CommonWebSocket.CreateServerWebSocket(opaqueTransport, subProtocol, keepAliveInterval, receiveBufferSize)); }
private static async Task <WebSocket> Upgrade(HttpContext context) { var upgradeFeature = context.Features.Get <IHttpUpgradeFeature>(); // Generate WebSocket response headers string key = context.Request.Headers[Constants.Headers.SecWebSocketKey].ToString(); var responseHeaders = HandshakeHelpers.GenerateResponseHeaders(key); foreach (var headerPair in responseHeaders) { context.Response.Headers[headerPair.Key] = headerPair.Value; } // Upgrade the connection Stream opaqueTransport = await upgradeFeature.UpgradeAsync(); // Get the WebSocket object var ws = WebSocket.CreateFromStream(opaqueTransport, isServer: true, subProtocol: null, keepAliveInterval: TimeSpan.FromMinutes(2)); return(ws); }
private bool IsMazeSocketRequest(HttpContext context, IHttpUpgradeFeature upgradeFeature) { if (!upgradeFeature.IsUpgradableRequest) { return(false); } if (!string.Equals(context.Request.Method, "GET", StringComparison.OrdinalIgnoreCase)) { return(false); } var headers = new List <KeyValuePair <string, string> >(); foreach (var headerName in HandshakeHelpers.NeededHeaders) { foreach (var value in context.Request.Headers.GetCommaSeparatedValues(headerName)) { headers.Add(new KeyValuePair <string, string>(headerName, value)); } } return(HandshakeHelpers.CheckSupportedRequest(headers)); }
public void CompressionNegotiateNotAccepted(string clientHeader) { Assert.False(HandshakeHelpers.ParseDeflateOptions(clientHeader.AsSpan(), serverContextTakeover: true, serverMaxWindowBits: 15, out var _, out var response)); }
public void CompressionNegotiationProducesCorrectHeaderWithCustomOptions(string clientHeader, string expectedResponse) { Assert.True(HandshakeHelpers.ParseDeflateOptions(clientHeader.AsSpan(), serverContextTakeover: false, serverMaxWindowBits: 14, out var _, out var response)); Assert.Equal(expectedResponse, response); }
public void RejectsInvalidRequestKeys(string key) { Assert.False(HandshakeHelpers.IsRequestKeyValid(key)); }
public void AcceptsValidRequestKeys(string key) { Assert.True(HandshakeHelpers.IsRequestKeyValid(key)); }
public async Task <WebSocket> AcceptAsync(WebSocketAcceptContext acceptContext) { if (!IsWebSocketRequest) { throw new InvalidOperationException("Not a WebSocket request."); } string? subProtocol = null; bool enableCompression = false; bool serverContextTakeover = true; int serverMaxWindowBits = 15; TimeSpan keepAliveInterval = _options.KeepAliveInterval; if (acceptContext != null) { subProtocol = acceptContext.SubProtocol; enableCompression = acceptContext.DangerousEnableCompression; serverContextTakeover = !acceptContext.DisableServerContextTakeover; serverMaxWindowBits = acceptContext.ServerMaxWindowBits; keepAliveInterval = acceptContext.KeepAliveInterval ?? keepAliveInterval; } #pragma warning disable CS0618 // Type or member is obsolete if (acceptContext is ExtendedWebSocketAcceptContext advancedAcceptContext) #pragma warning restore CS0618 // Type or member is obsolete { if (advancedAcceptContext.KeepAliveInterval.HasValue) { keepAliveInterval = advancedAcceptContext.KeepAliveInterval.Value; } } HandshakeHelpers.GenerateResponseHeaders(!_isH2WebSocket, _context.Request.Headers, subProtocol, _context.Response.Headers); WebSocketDeflateOptions?deflateOptions = null; if (enableCompression) { var ext = _context.Request.Headers.SecWebSocketExtensions; if (ext.Count != 0) { // loop over each extension offer, extensions can have multiple offers, we can accept any foreach (var extension in _context.Request.Headers.GetCommaSeparatedValues(HeaderNames.SecWebSocketExtensions)) { if (extension.AsSpan().TrimStart().StartsWith("permessage-deflate", StringComparison.Ordinal)) { if (HandshakeHelpers.ParseDeflateOptions(extension.AsSpan().TrimStart(), serverContextTakeover, serverMaxWindowBits, out var parsedOptions, out var response)) { Log.CompressionAccepted(_logger, response); deflateOptions = parsedOptions; // If more extension types are added, this would need to be a header append // and we wouldn't want to break out of the loop _context.Response.Headers.SecWebSocketExtensions = response; break; } } } if (deflateOptions is null) { Log.CompressionNotAccepted(_logger); } } } Stream opaqueTransport; // HTTP/2 if (_isH2WebSocket) { // Send the response headers opaqueTransport = await _connectFeature !.AcceptAsync(); } // HTTP/1.1 else { opaqueTransport = await _upgradeFeature !.UpgradeAsync(); // Sets status code to 101 } return(WebSocket.CreateFromStream(opaqueTransport, new WebSocketCreationOptions() { IsServer = true, KeepAliveInterval = keepAliveInterval, SubProtocol = subProtocol, DangerousDeflateOptions = deflateOptions })); }