File: Proxying\ConditionalProxyMiddleware.cs
Web Access
Project: src\src\Middleware\Spa\SpaServices.Extensions\src\Microsoft.AspNetCore.SpaServices.Extensions.csproj (Microsoft.AspNetCore.SpaServices.Extensions)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Net.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting;
 
namespace Microsoft.AspNetCore.SpaServices.Extensions.Proxy;
 
// This duplicates and updates the proxying logic in SpaServices so that we can update
// the project templates without waiting for 2.1 to ship. When 2.1 is ready to ship,
// merge the additional proxying features (e.g., proxying websocket connections) back
// into the SpaServices proxying code. It's all internal.
internal sealed class ConditionalProxyMiddleware
{
    private readonly RequestDelegate _next;
    private readonly Task<Uri> _baseUriTask;
    private readonly string _pathPrefix;
    private readonly bool _pathPrefixIsRoot;
    private readonly HttpClient _httpClient;
    private readonly CancellationToken _applicationStoppingToken;
 
    public ConditionalProxyMiddleware(
        RequestDelegate next,
        string pathPrefix,
        TimeSpan requestTimeout,
        Task<Uri> baseUriTask,
        IHostApplicationLifetime applicationLifetime)
    {
        if (!pathPrefix.StartsWith('/'))
        {
            pathPrefix = "/" + pathPrefix;
        }
 
        _next = next;
        _pathPrefix = pathPrefix;
        _pathPrefixIsRoot = string.Equals(_pathPrefix, "/", StringComparison.Ordinal);
        _baseUriTask = baseUriTask;
        _httpClient = SpaProxy.CreateHttpClientForProxy(requestTimeout);
        _applicationStoppingToken = applicationLifetime.ApplicationStopping;
    }
 
    public Task Invoke(HttpContext context)
    {
        if (context.Request.Path.StartsWithSegments(_pathPrefix) || _pathPrefixIsRoot)
        {
            return InvokeCore(context);
        }
        return _next.Invoke(context);
    }
 
    private async Task InvokeCore(HttpContext context)
    {
        var didProxyRequest = await SpaProxy.PerformProxyRequest(
            context, _httpClient, _baseUriTask, _applicationStoppingToken, proxy404s: false);
        if (didProxyRequest)
        {
            return;
        }
 
        // Not a request we can proxy
        await _next.Invoke(context);
    }
}