| File: Registry\DefaultBlobOperations.cs | Web Access |
| Project: src\sdk\src\Containers\Microsoft.NET.Build.Containers\Microsoft.NET.Build.Containers.csproj (Microsoft.NET.Build.Containers) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; using System.Net; using System.Text.Json.Nodes; using Microsoft.Extensions.Logging; using Microsoft.NET.Build.Containers.Resources; namespace Microsoft.NET.Build.Containers; internal class DefaultBlobOperations : IBlobOperations { private readonly Uri _baseUri; private readonly HttpClient _client; private readonly ILogger _logger; private readonly string _registryName; public DefaultBlobOperations(Uri baseUri, string registryName, HttpClient client, ILogger logger) { _baseUri = baseUri; _client = client; _logger = logger; _registryName = registryName; Upload = new DefaultBlobUploadOperations(_baseUri, _client, _logger); } public IBlobUploadOperations Upload { get; } public async Task<bool> ExistsAsync(string repositoryName, string digest, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); using HttpResponseMessage response = await _client.SendAsync(new HttpRequestMessage(HttpMethod.Head, new Uri(_baseUri, $"/v2/{repositoryName}/blobs/{digest}")), cancellationToken).ConfigureAwait(false); return response.StatusCode switch { HttpStatusCode.OK => true, HttpStatusCode.NotFound => false, HttpStatusCode.Unauthorized or HttpStatusCode.Forbidden => throw new UnableToAccessRepositoryException(_registryName, repositoryName), _ => await LogAndThrowContainerHttpException<bool>(response, cancellationToken).ConfigureAwait(false) }; } public async Task<JsonNode> GetJsonAsync(string repositoryName, string digest, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); HttpResponseMessage response = await GetAsync(repositoryName, digest, cancellationToken).ConfigureAwait(false); JsonNode? configDoc = JsonNode.Parse(await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false)); Debug.Assert(configDoc is not null); return configDoc; } public async Task<Stream> GetStreamAsync(string repositoryName, string digest, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); HttpResponseMessage response = await GetAsync(repositoryName, digest, cancellationToken).ConfigureAwait(false); return await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); } private async Task<HttpResponseMessage> GetAsync(string repositoryName, string digest, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); using HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(_baseUri, $"/v2/{repositoryName}/blobs/{digest}")).AcceptManifestFormats(); HttpResponseMessage response = await _client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); return response.StatusCode switch { HttpStatusCode.OK => response, HttpStatusCode.Unauthorized or HttpStatusCode.Forbidden => throw new UnableToAccessRepositoryException(_registryName, repositoryName), _ => await LogAndThrowContainerHttpException<HttpResponseMessage>(response, cancellationToken).ConfigureAwait(false) }; } private async Task<T> LogAndThrowContainerHttpException<T>(HttpResponseMessage response, CancellationToken cancellationToken) { await response.LogHttpResponseAsync(_logger, cancellationToken).ConfigureAwait(false); throw new ContainerHttpException(Resource.GetString(nameof(Strings.RegistryPullFailed)), response.RequestMessage?.RequestUri?.ToString(), response.StatusCode); } }