| File: UriUtility.cs | Web Access |
| Project: src\nuget-client\src\NuGet.Core\NuGet.Common\NuGet.Common.csproj (NuGet.Common) |
// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.IO; namespace NuGet.Common { public static class UriUtility { private const string FilePrefix = "file://"; private static bool IsHttpUrl(Uri uri) { return uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps; } /// <summary> /// Same as "new Uri" except that it can handle UNIX style paths that start with '/' /// </summary> public static Uri CreateSourceUri(string source, UriKind kind = UriKind.Absolute) { source = FixSourceUri(source); return new Uri(source, kind); } /// <summary> /// Same as "Uri.TryCreate" except that it can handle UNIX style paths that start with '/' /// </summary> public static Uri? TryCreateSourceUri(string source, UriKind kind) { source = FixSourceUri(source); Uri? uri; return Uri.TryCreate(source, kind, out uri) ? uri : null; } private static string FixSourceUri(string source) { // UNIX absolute paths need to start with file:// if (Path.DirectorySeparatorChar == '/' && !string.IsNullOrEmpty(source) && source[0] == '/') { source = FilePrefix + source; } return source; } /// <summary> /// Provides Uri encoding for V2 servers in the same way that NuGet.Core.dll encoded urls. /// </summary> public static string UrlEncodeOdataParameter(string value) { if (!string.IsNullOrEmpty(value)) { // OData requires that a single quote MUST be escaped as 2 single quotes. // In .NET 4.5, Uri.EscapeDataString() escapes single quote as %27. Thus we must replace %27 with 2 single quotes. // In .NET 4.0, Uri.EscapeDataString() doesn't escape single quote. Thus we must replace it with 2 single quotes. return Uri.EscapeDataString(value).Replace("'", "''").Replace("%27", "''"); } return value; } /// <summary> /// Convert a file:// URI to a local path. /// </summary> /// <returns>If the input can be parsed this will return Uri.LocalPath, if the input /// is not a URI or fails to parse the original string will be returned.</returns> /// <param name="localOrUriPath">Possible file:// URI path or local path.</param> public static string GetLocalPath(string localOrUriPath) { // check if this starts with file:// if (!string.IsNullOrEmpty(localOrUriPath) && localOrUriPath.StartsWith(FilePrefix, StringComparison.OrdinalIgnoreCase)) { // convert to a uri and get the local path Uri? uri; if (Uri.TryCreate(localOrUriPath, UriKind.RelativeOrAbsolute, out uri)) { return uri.LocalPath; } } // Return the same path return localOrUriPath; } /// <summary> /// Calls GetAbsolutePath with the directory of <paramref name="sourceFile"/>. /// </summary> public static string GetAbsolutePathFromFile(string? sourceFile, string path) { if (string.IsNullOrEmpty(sourceFile)) { return path; } return GetAbsolutePath(Path.GetDirectoryName(sourceFile!), path)!; } /// <summary> /// Convert a relative local folder path to an absolute path. /// For http sources and UNC shares this will return /// the same path. /// </summary> /// <param name="rootDirectory">Directory to make the source relative to.</param> /// <param name="path">Source path.</param> /// <returns>The absolute source path or the original source. Noops for non-file paths.</returns> public static string? GetAbsolutePath(string? rootDirectory, string? path) { // return invalid data as-is. if (string.IsNullOrEmpty(rootDirectory) || string.IsNullOrEmpty(path)) { return path; } // Convert file:// to a path var local = GetLocalPath(path!); // Check if the result is relative, in which case combine it. var relativeUri = TryCreateSourceUri(local, UriKind.Relative); if (relativeUri != null) { // .NET has multithreaded MSBuild where the process CWD is shared, so resolution must not depend on it. #if !NETFRAMEWORK // Anchor to rootDirectory; Path.Combine would leak the CWD/drive for rooted-but-relative "local" like "C:" or "\foo". return Path.IsPathFullyQualified(rootDirectory) ? Path.GetFullPath(local, rootDirectory) : Path.GetFullPath(Path.Combine(rootDirectory, local)); #else return Path.GetFullPath(Path.Combine(rootDirectory, local)); #endif } var absoluteUri = TryCreateSourceUri(local, UriKind.Absolute); if (absoluteUri?.IsFile == true) { return Path.GetFullPath(local); } // Absolute path or non-http url. return local; } /// <summary> /// Determines if a package source url points to nuget.org /// </summary> /// <param name="source">Package source url</param> /// <returns>True if the source is HTTP and has a *.nuget.org or nuget.org host otherwise false</returns> public static bool IsNuGetOrg(string? source) { if (string.IsNullOrWhiteSpace(source)) { return false; } var uri = TryCreateSourceUri(source!, UriKind.Absolute); if (uri == null || !IsHttpUrl(uri)) { return false; } if (StringComparer.OrdinalIgnoreCase.Equals(uri.Host, "nuget.org") || uri.Host.EndsWith(".nuget.org", StringComparison.OrdinalIgnoreCase)) { return true; } return false; } } }