public UpgradeHandshake( HttpContext context, IHttpUpgradeFeature upgradeFeature) { _context = context; _upgradeFeature = upgradeFeature; }
public WebSocketRequest(HttpContext context, IHttpUpgradeFeature upgradeFeature) { Context = context; IsWebSocketRequest = upgradeFeature.IsUpgradableRequest && CheckSupportedWebSocketRequest(); _upgradeFeature = upgradeFeature; }
public WebSocketConnectionFeature(HttpContext context, ChannelFactory channelFactory, IHttpUpgradeFeature upgradeFeature, ILoggerFactory loggerFactory) { _channelFactory = channelFactory; _context = context; _upgradeFeature = upgradeFeature; _logger = loggerFactory.CreateLogger <WebSocketConnectionFeature>(); }
public UpgradeHandshake(HttpContext context, IHttpUpgradeFeature upgradeFeature, WebSocketOptions options, ILogger logger) { _context = context; _upgradeFeature = upgradeFeature; _options = options; _logger = logger; }
public UpgradeFeatureLoggingDecorator(IHttpUpgradeFeature innerUpgradeFeature, HttpResponse response, HttpLoggingOptions options, ILogger logger) { _innerUpgradeFeature = innerUpgradeFeature ?? throw new ArgumentNullException(nameof(innerUpgradeFeature)); _response = response ?? throw new ArgumentNullException(nameof(response)); _options = options ?? throw new ArgumentNullException(nameof(options)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); }
public MazeSocketUpgrader(HttpContext context, IHttpUpgradeFeature upgradeFeature, MazeSocketOptions options) { _context = context; _upgradeFeature = upgradeFeature; _options = options; }
public WebSocketRequest(HttpContext context, IHttpUpgradeFeature upgradeFeature, WebSocketServerOptions options, ILogger logger) { Context = context; IsWebSocketRequest = upgradeFeature.IsUpgradableRequest && CheckSupportedWebSocketRequest(); m_upgradeFeature = upgradeFeature; m_options = options; m_logger = logger; }
public WebSocketRequest(HttpContext context, IHttpUpgradeFeature upgradeFeature) { _context = context; _upgradeFeature = upgradeFeature; if (upgradeFeature.IsUpgradableRequest) { IsWebSocketRequest = CheckSupportedWebSocketRequest(); } }
/// <summary> /// Process an individual request. /// </summary> /// <param name="context">The context.</param> /// <returns>The task object representing the asynchronous operation.</returns> public Task Invoke(HttpContext context) { IHttpUpgradeFeature upgradeFeature = context.Features.Get <IHttpUpgradeFeature>(); if (upgradeFeature != null) { context.Features.Set <IHttpWebSocketFeature>(new HttpWebSocketCompressionFeature(context, upgradeFeature, _options)); } return(_next(context)); }
public async Task OriginalUpgradeFeatureIsRestoredBeforeMiddlewareCompletes(HttpLoggingFields loggingFields) { var options = CreateOptionsAccessor(); options.CurrentValue.LoggingFields = loggingFields; var letBodyFinish = new TaskCompletionSource(); var httpContext = new DefaultHttpContext(); var upgradeFeatureMock = new Mock <IHttpUpgradeFeature>(); upgradeFeatureMock.Setup(m => m.IsUpgradableRequest).Returns(true); upgradeFeatureMock.Setup(m => m.UpgradeAsync()).ReturnsAsync(Stream.Null); httpContext.Features.Set <IHttpUpgradeFeature>(upgradeFeatureMock.Object); IHttpUpgradeFeature upgradeFeature = null; var middleware = new HttpLoggingMiddleware( async c => { upgradeFeature = c.Features.Get <IHttpUpgradeFeature>(); await letBodyFinish.Task; }, options, LoggerFactory.CreateLogger <HttpLoggingMiddleware>()); var middlewareTask = middleware.Invoke(httpContext); Assert.True(upgradeFeature is UpgradeFeatureLoggingDecorator); letBodyFinish.SetResult(); await middlewareTask; Assert.False(httpContext.Features.Get <IHttpUpgradeFeature>() is UpgradeFeatureLoggingDecorator); }
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)); }
internal HttpWebSocketCompressionFeature(HttpContext context, IHttpUpgradeFeature upgradeFeature, WebSocketCompressionOptions options) { _context = context ?? throw new ArgumentNullException(nameof(context)); _upgradeFeature = upgradeFeature ?? throw new ArgumentNullException(nameof(upgradeFeature)); _options = options ?? throw new ArgumentNullException(nameof(options)); }
/// <summary> /// Proxies an upgradable request to the upstream server, treating the upgraded stream as an opaque duplex channel. /// </summary> /// <remarks> /// Upgradable request proxying comprises the following steps: /// (1) Create outgoing HttpRequestMessage /// (2) Copy request headers Downstream ---► Proxy ---► Upstream /// (3) Send the outgoing request using HttpMessageInvoker Downstream ---► Proxy ---► Upstream /// (4) Copy response status line Downstream ◄--- Proxy ◄--- Upstream /// (5) Copy response headers Downstream ◄--- Proxy ◄--- Upstream /// Scenario A: upgrade with upstream worked (got 101 response) /// (A-6) Upgrade downstream channel (also sends response headers) Downstream ◄--- Proxy ◄--- Upstream /// (A-7) Copy duplex streams Downstream ◄--► Proxy ◄--► Upstream /// ---- or ---- /// Scenario B: upgrade with upstream failed (got non-101 response) /// (B-6) Send response headers Downstream ◄--- Proxy ◄--- Upstream /// (B-7) Copy response body Downstream ◄--- Proxy ◄--- Upstream /// /// This takes care of WebSockets as well as any other upgradable protocol. /// </remarks> private async Task UpgradableProxyAsync( HttpContext context, IHttpUpgradeFeature upgradeFeature, Uri targetUri, HttpMessageInvoker httpClient, ProxyTelemetryContext proxyTelemetryContext, CancellationToken shortCancellation, CancellationToken longCancellation) { Contracts.CheckValue(context, nameof(context)); Contracts.CheckValue(upgradeFeature, nameof(upgradeFeature)); Contracts.CheckValue(targetUri, nameof(targetUri)); Contracts.CheckValue(httpClient, nameof(httpClient)); // ::::::::::::::::::::::::::::::::::::::::::::: // :: Step 1: Create outgoing HttpRequestMessage var upstreamRequest = new HttpRequestMessage(HttpUtilities.GetHttpMethod(context.Request.Method), targetUri) { // Default to HTTP/1.1 for proxying upgradable requests. This is already the default as of .NET Core 3.1 Version = new Version(1, 1), }; // ::::::::::::::::::::::::::::::::::::::::::::: // :: Step 2: Copy request headers Downstream --► Proxy --► Upstream CopyHeadersToUpstream(context, upstreamRequest); // ::::::::::::::::::::::::::::::::::::::::::::: // :: Step 3: Send the outgoing request using HttpMessageInvoker var upstreamResponse = await httpClient.SendAsync(upstreamRequest, shortCancellation); var upgraded = upstreamResponse.StatusCode == HttpStatusCode.SwitchingProtocols && upstreamResponse.Content != null; // ::::::::::::::::::::::::::::::::::::::::::::: // :: Step 4: Copy response status line Downstream ◄-- Proxy ◄-- Upstream context.Response.StatusCode = (int)upstreamResponse.StatusCode; context.Features.Get <IHttpResponseFeature>().ReasonPhrase = upstreamResponse.ReasonPhrase; // ::::::::::::::::::::::::::::::::::::::::::::: // :: Step 5: Copy response headers Downstream ◄-- Proxy ◄-- Upstream CopyHeadersToDownstream(upstreamResponse, context.Response.Headers); if (!upgraded) { // ::::::::::::::::::::::::::::::::::::::::::::: // :: Step B-6: Send response headers Downstream ◄-- Proxy ◄-- Upstream // This is important to avoid any extra delays in sending response headers // e.g. if the upstream server is slow to provide its response body. await context.Response.StartAsync(shortCancellation); // ::::::::::::::::::::::::::::::::::::::::::::: // :: Step B-7: Copy response body Downstream ◄-- Proxy ◄-- Upstream await CopyBodyDownstreamAsync(upstreamResponse.Content, context.Response.Body, proxyTelemetryContext, longCancellation); return; } // ::::::::::::::::::::::::::::::::::::::::::::: // :: Step A-6: Upgrade the downstream channel. This will send all response headers too. using var downstreamStream = await upgradeFeature.UpgradeAsync(); // ::::::::::::::::::::::::::::::::::::::::::::: // :: Step A-7: Copy duplex streams var upstreamStream = await upstreamResponse.Content.ReadAsStreamAsync(); var upstreamCopier = new StreamCopier( _metrics, new StreamCopyTelemetryContext( direction: "upstream", backendId: proxyTelemetryContext.BackendId, routeId: proxyTelemetryContext.RouteId, destinationId: proxyTelemetryContext.DestinationId)); var upstreamTask = upstreamCopier.CopyAsync(downstreamStream, upstreamStream, longCancellation); var downstreamCopier = new StreamCopier( _metrics, new StreamCopyTelemetryContext( direction: "downstream", backendId: proxyTelemetryContext.BackendId, routeId: proxyTelemetryContext.RouteId, destinationId: proxyTelemetryContext.DestinationId)); var downstreamTask = downstreamCopier.CopyAsync(upstreamStream, downstreamStream, longCancellation); await Task.WhenAll(upstreamTask, downstreamTask); }
public UpgradeHandshake(HttpContext context, IHttpUpgradeFeature upgradeFeature, WebSocketOptions options) { _context = context; _upgradeFeature = upgradeFeature; _options = options; }
/// <summary> /// Proxies an upgradable request to the upstream server, treating the upgraded stream as an opaque duplex channel. /// </summary> /// <remarks> /// Upgradable request proxying comprises the following steps: /// (1) Create outgoing HttpRequestMessage /// (2) Copy request headers Downstream ---► Proxy ---► Upstream /// (3) Send the outgoing request using HttpMessageInvoker Downstream ---► Proxy ---► Upstream /// (4) Copy response status line Downstream ◄--- Proxy ◄--- Upstream /// (5) Copy response headers Downstream ◄--- Proxy ◄--- Upstream /// Scenario A: upgrade with upstream worked (got 101 response) /// (A-6) Upgrade downstream channel (also sends response headers) Downstream ◄--- Proxy ◄--- Upstream /// (A-7) Copy duplex streams Downstream ◄--► Proxy ◄--► Upstream /// ---- or ---- /// Scenario B: upgrade with upstream failed (got non-101 response) /// (B-6) Send response headers Downstream ◄--- Proxy ◄--- Upstream /// (B-7) Copy response body Downstream ◄--- Proxy ◄--- Upstream /// /// This takes care of WebSockets as well as any other upgradable protocol. /// </remarks> private async Task UpgradableProxyAsync( HttpContext context, IHttpUpgradeFeature upgradeFeature, HttpRequestMessage upstreamRequest, HttpMessageInvoker httpClient, CancellationToken shortCancellation, CancellationToken longCancellation, Action <HttpRequestMessage> requestAction = null) { _ = context ?? throw new ArgumentNullException(nameof(context)); _ = upgradeFeature ?? throw new ArgumentNullException(nameof(upgradeFeature)); _ = upstreamRequest ?? throw new ArgumentNullException(nameof(upstreamRequest)); _ = httpClient ?? throw new ArgumentNullException(nameof(httpClient)); // ::::::::::::::::::::::::::::::::::::::::::::: // :: Step 2: Copy request headers Downstream --► Proxy --► Upstream CopyHeadersToUpstream(context, upstreamRequest); if (requestAction != null) { requestAction(upstreamRequest); } // ::::::::::::::::::::::::::::::::::::::::::::: // :: Step 3: Send the outgoing request using HttpMessageInvoker var upstreamResponse = await httpClient.SendAsync(upstreamRequest, shortCancellation); var upgraded = upstreamResponse.StatusCode == HttpStatusCode.SwitchingProtocols && upstreamResponse.Content != null; // ::::::::::::::::::::::::::::::::::::::::::::: // :: Step 4: Copy response status line Downstream ◄-- Proxy ◄-- Upstream context.Response.StatusCode = (int)upstreamResponse.StatusCode; context.Features.Get <IHttpResponseFeature>().ReasonPhrase = upstreamResponse.ReasonPhrase; // ::::::::::::::::::::::::::::::::::::::::::::: // :: Step 5: Copy response headers Downstream ◄-- Proxy ◄-- Upstream CopyHeadersToDownstream(upstreamResponse, context); if (!upgraded) { // ::::::::::::::::::::::::::::::::::::::::::::: // :: Step B-6: Send response headers Downstream ◄-- Proxy ◄-- Upstream // This is important to avoid any extra delays in sending response headers // e.g. if the upstream server is slow to provide its response body. await context.Response.StartAsync(shortCancellation); // ::::::::::::::::::::::::::::::::::::::::::::: // :: Step B-7: Copy response body Downstream ◄-- Proxy ◄-- Upstream await CopyBodyDownstreamAsync(upstreamResponse.Content, context.Response.Body, longCancellation); return; } // ::::::::::::::::::::::::::::::::::::::::::::: // :: Step A-6: Upgrade the downstream channel. This will send all response headers too. using var downstreamStream = await upgradeFeature.UpgradeAsync(); // ::::::::::::::::::::::::::::::::::::::::::::: // :: Step A-7: Copy duplex streams var upstreamStream = await upstreamResponse.Content.ReadAsStreamAsync(); var upstreamCopier = new StreamCopier(); var upstreamTask = upstreamCopier.CopyAsync(downstreamStream, upstreamStream, longCancellation); var downstreamCopier = new StreamCopier(); var downstreamTask = downstreamCopier.CopyAsync(upstreamStream, downstreamStream, longCancellation); await Task.WhenAll(upstreamTask, downstreamTask); }
public HttpUpgradeFeatureWrapper(IClock clock, HttpContext httpContext, IHttpUpgradeFeature upgradeFeature) { _clock = clock ?? throw new ArgumentNullException(nameof(clock)); HttpContext = httpContext ?? throw new ArgumentNullException(nameof(httpContext)); InnerUpgradeFeature = upgradeFeature ?? throw new ArgumentNullException(nameof(upgradeFeature)); }
public UpgradeHandshake(HttpContext context, IHttpUpgradeFeature upgradeFeature, WebSocketOptions options) { _context = context; _upgradeFeature = upgradeFeature; _options = options; }
private async Task DoWebSocket(HttpContext context, IHttpUpgradeFeature upgrade) { var service = context.Features.Get <IService>(); var endPoint = service.IpEndPoint; var socket = await System.IO.Pipelines.Networking.Sockets.SocketConnection.ConnectAsync(endPoint, _factory); try { var writer = socket.Output.Alloc(); writer.Append(context.Request.Method, TextEncoder.Utf8); writer.Write(_space); writer.Append(context.Request.Path.Value, TextEncoder.Utf8); writer.Write(_space); writer.Append(context.Request.Protocol, TextEncoder.Utf8); writer.Write(_endOfLine); foreach (var header in context.Request.Headers) { writer.Append(header.Key, TextEncoder.Utf8); writer.Write(_headerSplit); writer.Append(string.Join(", ", (IEnumerable <string>)header.Value), TextEncoder.Utf8); writer.Write(_endOfLine); } writer.Write(_endOfLine); await writer.FlushAsync(); while (true) { var reader = await socket.Input.ReadAsync(); var buffer = reader.Buffer; try { if (!buffer.TrySliceTo(_headersEnd, out ReadableBuffer headers, out ReadCursor cursor)) { continue; } buffer = buffer.Slice(cursor).Slice(_headersEnd.Length); if (!headers.TrySliceTo(_endOfLine, out ReadableBuffer line, out cursor)) { throw new InvalidOperationException(); } headers = headers.Slice(cursor).Slice(_endOfLine.Length); while (headers.Length > 0) { if (!headers.TrySliceTo(_endOfLine, out ReadableBuffer headerLine, out cursor)) { headerLine = headers; headers = headers.Slice(headers.Length); } else { headers = headers.Slice(cursor).Slice(_endOfLine.Length); } if (!headerLine.TrySliceTo(_headerSplit, out ReadableBuffer key, out cursor)) { throw new NotImplementedException(); } var values = headerLine.Slice(cursor).Slice(_headerSplit.Length).GetUtf8String().Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries); context.Response.Headers[key.GetUtf8String()] = new Microsoft.Extensions.Primitives.StringValues(values); } break; } finally { socket.Input.Advance(buffer.Start, buffer.End); } }