File: Registry\RegistrySettings.cs
Web Access
Project: ..\..\..\src\Containers\Microsoft.NET.Build.Containers\Microsoft.NET.Build.Containers.csproj (Microsoft.NET.Build.Containers)
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
 
using Microsoft.DotNet.Cli.Utils;
 
namespace Microsoft.NET.Build.Containers;
 
internal class RegistrySettings
{
    public RegistrySettings(string? registryName = null, IEnvironmentProvider? environment = null)
    {
        environment ??= new EnvironmentProvider();
 
        ChunkedUploadSizeBytes = environment.GetEnvironmentVariableAsNullableInt(EnvVariables.ChunkedUploadSizeBytes) ??
            environment.GetEnvironmentVariableAsNullableInt(EnvVariables.ChunkedUploadSizeBytesLegacy);
        ForceChunkedUpload = Environment.GetEnvironmentVariable(EnvVariables.ForceChunkedUpload) is not null ?
            environment.GetEnvironmentVariableAsBool(EnvVariables.ForceChunkedUpload, defaultValue: false) :
            environment.GetEnvironmentVariableAsBool(EnvVariables.ForceChunkedUploadLegacy, defaultValue: false);
        ParallelUploadEnabled = Environment.GetEnvironmentVariable(EnvVariables.ParallelUploadEnabled) is not null ?
            environment.GetEnvironmentVariableAsBool(EnvVariables.ParallelUploadEnabled, defaultValue: true) :
            environment.GetEnvironmentVariableAsBool(EnvVariables.ParallelUploadEnabledLegacy, defaultValue: true);
 
        if (registryName is not null)
        {
            IsInsecure = IsInsecureRegistry(environment, registryName);
        }
    }
 
    private const int DefaultChunkSizeBytes = 1024 * 64;
    private const int FiveMegs = 5_242_880;
 
    /// <summary>
    /// When chunking is enabled, allows explicit control over the size of the chunks uploaded
    /// </summary>
    /// <remarks>
    /// Our default of 64KB is very conservative, so raising this to 1MB or more can speed up layer uploads reasonably well.
    /// </remarks>
    internal int? ChunkedUploadSizeBytes { get; init; }
 
    /// <summary>
    /// Allows to force chunked upload for debugging purposes.
    /// </summary>
    internal bool ForceChunkedUpload { get; init; }
 
    /// <summary>
    /// Whether we should upload blobs in parallel (enabled by default, but disabled for certain registries in conjunction with the explicit support check below).
    /// </summary>
    /// <remarks>
    /// Enabling this can swamp some registries, so this is an escape hatch.
    /// </remarks>
    internal bool ParallelUploadEnabled { get; init; }
 
    /// <summary>
    /// Allows ignoring https certificate errors and changing to http when the endpoint is not an https endpoint.
    /// </summary>
    internal bool IsInsecure { get; init; }
 
    internal struct EnvVariables
    {
        internal const string ChunkedUploadSizeBytes = "DOTNET_CONTAINER_REGISTRY_CHUNKED_UPLOAD_SIZE_BYTES";
        internal const string ChunkedUploadSizeBytesLegacy = "SDK_CONTAINER_REGISTRY_CHUNKED_UPLOAD_SIZE_BYTES";
 
        internal const string ForceChunkedUpload = "DOTNET_CONTAINER_DEBUG_REGISTRY_FORCE_CHUNKED_UPLOAD";
        internal const string ForceChunkedUploadLegacy = "SDK_CONTAINER_DEBUG_REGISTRY_FORCE_CHUNKED_UPLOAD";
        internal const string ParallelUploadEnabled = "DOTNET_CONTAINER_REGISTRY_PARALLEL_UPLOAD";
        internal const string ParallelUploadEnabledLegacy = "SDK_CONTAINER_REGISTRY_PARALLEL_UPLOAD";
 
        internal const string InsecureRegistries = "DOTNET_CONTAINER_INSECURE_REGISTRIES";
    }
 
    private static bool IsInsecureRegistry(IEnvironmentProvider environment, string registryName)
    {
        // Always allow insecure access to 'localhost'.
        if (registryName.StartsWith("localhost:", StringComparison.OrdinalIgnoreCase) ||
            registryName.Equals("localhost", StringComparison.OrdinalIgnoreCase))
        {
            return true;
        }
 
        // DOTNET_CONTAINER_INSECURE_REGISTRIES is a semicolon separated list of insecure registry names.
        string? insecureRegistriesEnv = environment.GetEnvironmentVariable(EnvVariables.InsecureRegistries);
        if (insecureRegistriesEnv is not null)
        {
            string[] insecureRegistries = insecureRegistriesEnv.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
            if (Array.Exists(insecureRegistries, registry => registryName.Equals(registry, StringComparison.OrdinalIgnoreCase)))
            {
                return true;
            }
        }
 
        return DockerCli.IsInsecureRegistry(registryName);
    }
}