| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | using Google.Apis.Util; |
| | using System; |
| | using System.Collections.Generic; |
| | using System.Linq; |
| | using System.Reflection; |
| | using System.Runtime.Versioning; |
| |
|
| | namespace Google.Apis.Requests |
| | { |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | public sealed class VersionHeaderBuilder |
| | { |
| | private static readonly Lazy<string> s_environmentVersion = new Lazy<string>(GetEnvironmentVersion); |
| |
|
| | |
| | |
| | |
| | public const string HeaderName = "x-goog-api-client"; |
| | private readonly List<string> _names = new List<string>(); |
| | private readonly List<string> _values = new List<string>(); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | public VersionHeaderBuilder AppendVersion(string name, string version) |
| | { |
| | Utilities.ThrowIfNull(name, nameof(name)); |
| | Utilities.ThrowIfNull(version, nameof(version)); |
| | |
| |
|
| | CheckArgument(name.Length > 0 && !name.Contains(" ") && !name.Contains("/"), nameof(name), $"Invalid name: {name}"); |
| | CheckArgument(!version.Contains(" ") && !version.Contains("/"), nameof(version), $"Invalid version: {version}"); |
| | CheckArgument(!_names.Contains(name), nameof(name), "Names in version headers must be unique"); |
| | _names.Add(name); |
| | _values.Add(version); |
| | return this; |
| | } |
| |
|
| | |
| | private static void CheckArgument(bool condition, string paramName, string message) |
| | { |
| | if (!condition) |
| | { |
| | throw new ArgumentException(message, paramName); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | public VersionHeaderBuilder AppendAssemblyVersion(string name, System.Type type) |
| | => AppendVersion(name, FormatAssemblyVersion(type)); |
| |
|
| | |
| | |
| | |
| | public VersionHeaderBuilder AppendDotNetEnvironment() => AppendVersion("gl-dotnet", s_environmentVersion.Value); |
| |
|
| | |
| | |
| | |
| | private static bool IsHeaderNameValueValid(string nameOrValue) => |
| | !nameOrValue.Contains(" ") && !nameOrValue.Contains("/"); |
| |
|
| | private static string GetEnvironmentVersion() |
| | { |
| | |
| | |
| | string systemEnvironmentVersion = FormatVersion(Environment.Version); |
| | string entryAssemblyVersion = GetEntryAssemblyVersionOrNull(); |
| |
|
| | return entryAssemblyVersion ?? systemEnvironmentVersion ?? ""; |
| | } |
| |
|
| | private static string GetEntryAssemblyVersionOrNull() |
| | { |
| | try |
| | { |
| | |
| | |
| | var getEntryAssemblyMethod = typeof(Assembly) |
| | .GetTypeInfo() |
| | .DeclaredMethods |
| | .Where(m => m.Name == "GetEntryAssembly" && m.IsStatic && m.GetParameters().Length == 0 && m.ReturnType == typeof(Assembly)) |
| | .FirstOrDefault(); |
| | if (getEntryAssemblyMethod == null) |
| | { |
| | return null; |
| | } |
| | Assembly entryAssembly = (Assembly) getEntryAssemblyMethod.Invoke(null, new object[0]); |
| | var frameworkName = entryAssembly?.GetCustomAttribute<TargetFrameworkAttribute>()?.FrameworkName; |
| | return frameworkName == null ? null : FormatVersion(new FrameworkName(frameworkName).Version); |
| | } |
| | catch |
| | { |
| | |
| | return null; |
| | } |
| | } |
| |
|
| | private static string FormatAssemblyVersion(System.Type type) |
| | { |
| | |
| | |
| |
|
| | var assembly = type.GetTypeInfo().Assembly; |
| | var info = assembly.GetCustomAttributes<AssemblyInformationalVersionAttribute>().FirstOrDefault()?.InformationalVersion; |
| | if (info != null && IsHeaderNameValueValid(info)) |
| | { |
| | return FormatInformationalVersion(info); |
| | } |
| | var file = assembly.GetCustomAttributes<AssemblyFileVersionAttribute>().FirstOrDefault()?.Version; |
| | if (file != null) |
| | { |
| | return string.Join(".", file.Split('.').Take(3)); |
| | } |
| | return FormatVersion(assembly.GetName().Version); |
| | } |
| |
|
| | |
| |
|
| | |
| | |
| | |
| | |
| | internal static string FormatInformationalVersion(string info) |
| | { |
| | |
| | |
| | int signIndex = Math.Max(info.LastIndexOf('.'), info.LastIndexOf('+')); |
| | if (signIndex == -1 || signIndex != info.Length - 41) |
| | { |
| | return info; |
| | } |
| | for (int i = signIndex + 1; i < info.Length; i++) |
| | { |
| | char c = info[i]; |
| | bool isHex = (c >= '0' && c <= '9') |
| | || (c >= 'a' && c <= 'f') |
| | || (c >= 'A' && c <= 'F'); |
| | if (!isHex) |
| | { |
| | return info; |
| | } |
| | } |
| | return info.Substring(0, signIndex); |
| | } |
| |
|
| | private static string FormatVersion(Version version) => |
| | version != null ? |
| | $"{version.Major}.{version.Minor}.{(version.Build != -1 ? version.Build : 0)}" : |
| | ""; |
| |
|
| | |
| | public override string ToString() => string.Join(" ", _names.Zip(_values, (name, value) => $"{name}/{value}")); |
| |
|
| | |
| | |
| | |
| | |
| | public VersionHeaderBuilder Clone() |
| | { |
| | var ret = new VersionHeaderBuilder(); |
| | ret._names.AddRange(_names); |
| | ret._values.AddRange(_values); |
| | return ret; |
| | } |
| | } |
| | } |
| |
|