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 CompressionNegotiateNotAccepted(string clientHeader) { Assert.False(HandshakeHelpers.ParseDeflateOptions(clientHeader.AsSpan(), serverContextTakeover: true, serverMaxWindowBits: 15, out var _, out var response)); }
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 })); }