| File: TestServices\GitAuthenticationServer.cs | Web Access |
| Project: src\tests\Aspire.Cli.Tests\Aspire.Cli.Tests.csproj (Aspire.Cli.Tests) |
// 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; using System.Net.Sockets; using System.Text; namespace Aspire.Cli.Tests.TestServices; internal sealed class GitAuthenticationServer : IAsyncDisposable { private readonly TcpListener _listener = new(IPAddress.Loopback, 0); private readonly CancellationTokenSource _shutdown = new(); private readonly Task _run; private int _requests; public GitAuthenticationServer() { _listener.Start(); Repository = $"http://127.0.0.1:{((IPEndPoint)_listener.LocalEndpoint).Port}/repository"; _run = RunAsync(); } public string Repository { get; } public int Requests => Volatile.Read(ref _requests); private async Task RunAsync() { try { while (true) { using var client = await _listener.AcceptTcpClientAsync(_shutdown.Token); await using var stream = client.GetStream(); using var reader = new StreamReader(stream, Encoding.ASCII, leaveOpen: true); // Git sends GET /repository/info/refs?service=git-upload-pack // followed by HTTP headers and an empty line. Never record credentials. while (await reader.ReadLineAsync(_shutdown.Token) is { Length: > 0 }) { } Interlocked.Increment(ref _requests); await stream.WriteAsync( "HTTP/1.1 401 Unauthorized\r\nWWW-Authenticate: Basic realm=\"cli-test\"\r\nContent-Length: 0\r\nConnection: close\r\n\r\n"u8.ToArray(), _shutdown.Token); } } catch (OperationCanceledException) when (_shutdown.IsCancellationRequested) { } } public async ValueTask DisposeAsync() { await _shutdown.CancelAsync(); try { await _run; } finally { _listener.Stop(); _shutdown.Dispose(); } } }