/// <summary> /// Searches package sources given name and version information /// /// Package information must be returned using <c>request.YieldPackage(...)</c> function. /// </summary> /// <param name="name">a name or partial name of the package(s) requested</param> /// <param name="requiredVersion">A specific version of the package. Null or empty if the user did not specify</param> /// <param name="minimumVersion">A minimum version of the package. Null or empty if the user did not specify</param> /// <param name="maximumVersion">A maximum version of the package. Null or empty if the user did not specify</param> /// <param name="id">if this is greater than zero (and the number should have been generated using <c>StartFind(...)</c>, the core is calling this multiple times to do a batch search request. The operation can be delayed until <c>CompleteFind(...)</c> is called</param> /// <param name="request">An object passed in from the PackageManagement that contains functions that can be used to interact with its Provider</param> public void FindPackage(string name, string requiredVersion, string minimumVersion, string maximumVersion, int id, NuGetRequest request) { if (request == null) { throw new ArgumentNullException("request"); } // true if we want to include the max and min version bool minInclusive = true; bool maxInclusive = true; // If finding by canonical id, then the version follows dependency version requirement if (request.GetOptionValue("FindByCanonicalId").IsTrue()) { // Use the dependency version if no min and max is supplied if (String.IsNullOrWhiteSpace(maximumVersion) && String.IsNullOrWhiteSpace(minimumVersion)) { DependencyVersion depVers = DependencyVersion.ParseDependencyVersion(requiredVersion); maximumVersion = depVers.MaxVersion.ToStringSafe(); minimumVersion = depVers.MinVersion.ToStringSafe(); minInclusive = depVers.IsMinInclusive; maxInclusive = depVers.IsMaxInclusive; // set required version if we have both min max as the same value. if (depVers.MaxVersion != null && depVers.MinVersion != null && depVers.MaxVersion == depVers.MinVersion && minInclusive && maxInclusive) { requiredVersion = maximumVersion; } else { requiredVersion = null; } } } request.Debug(Resources.Messages.DebugInfoCallMethod, PackageProviderName, string.Format(CultureInfo.InvariantCulture, "FindPackage' - name='{0}', requiredVersion='{1}',minimumVersion='{2}', maximumVersion='{3}'", name, requiredVersion, minimumVersion, maximumVersion)); NormalizeVersion(request, ref requiredVersion, ref minimumVersion, ref maximumVersion); // First call to SearchPackages will just look for the packages with current credentials if (SearchPackages(name, requiredVersion, minimumVersion, maximumVersion, minInclusive, maxInclusive, id, request)) { return; } if (request.CredentialUsername.IsNullOrEmpty()) { // If no packages were found, try again using credentials retrieved from credential provider // First call to the credential provider is to get credentials, but if those credentials fail, // we call the cred provider again to ask the user for new credentials, and then search pkgs again using new creds var query = new Uri(request.FindRegisteredSource(request.Sources.First()).Location.IsNullOrEmpty() ? request.Sources.First() : request.FindRegisteredSource(request.Sources.First()).Location); var credentials = request.GetCredsFromCredProvider(query.AbsoluteUri, request, false); var newclient = PathUtility.GetHttpClientHelper(credentials.UserName, credentials.SecurePassword, request.WebProxy); request.SetHttpClient(newclient); if (SearchPackages(name, requiredVersion, minimumVersion, maximumVersion, minInclusive, maxInclusive, id, request)) { return; } // Calling the credential provider for a second time, using -IsRetry credentials = request.GetCredsFromCredProvider(query.AbsoluteUri, request, true); newclient = PathUtility.GetHttpClientHelper(credentials.UserName, credentials.SecurePassword, request.WebProxy); request.SetHttpClient(newclient); if (SearchPackages(name, requiredVersion, minimumVersion, maximumVersion, minInclusive, maxInclusive, id, request)) { return; } } }
/// <summary> /// Returns the validated uri. Returns null if we cannot validate it /// </summary> /// <param name="query"></param> /// <param name="request"></param> /// <returns></returns> internal static Uri ValidateUri(Uri query, NuGetRequest request) { // Validation takes place in two steps: // 1. Validate the given URI is valid, resolving redirection // 2. Validate we can hit the query service NetworkCredential credentials = null; var client = request.ClientWithoutAcceptHeader; var response = PathUtility.GetHttpResponse(client, query.AbsoluteUri, (() => request.IsCanceled), ((msg, num) => request.Verbose(Resources.Messages.RetryingDownload, msg, num)), (msg) => request.Verbose(msg), (msg) => request.Debug(msg)); if (response == null) { return(null); } // if response is not success, we need to check for redirection if (!response.IsSuccessStatusCode) { // Check for redirection (http status code 3xx) if (response.StatusCode == HttpStatusCode.MultipleChoices || response.StatusCode == HttpStatusCode.MovedPermanently || response.StatusCode == HttpStatusCode.Found || response.StatusCode == HttpStatusCode.SeeOther || response.StatusCode == HttpStatusCode.TemporaryRedirect) { // get the redirected direction string location = response.Headers.GetValues("Location").FirstOrDefault(); if (String.IsNullOrWhiteSpace(location)) { return(null); } // make a new query based on location query = new Uri(location); } else { if (response.StatusCode == HttpStatusCode.Unauthorized) { // If the uri is not validated, try again using credentials retrieved from credential provider // First call to the credential provider is to get credentials, but if those credentials fail, // we call the cred provider again to ask the user for new credentials, and then search try to validate uri again using new creds credentials = request.GetCredsFromCredProvider(query.AbsoluteUri.ToString(), request, false); var newClient = PathUtility.GetHttpClientHelper(credentials.UserName, credentials.SecurePassword, null); var newResponse = PathUtility.GetHttpResponse(newClient, query.AbsoluteUri, (() => request.IsCanceled), ((msg, num) => request.Verbose(Resources.Messages.RetryingDownload, msg, num)), (msg) => request.Verbose(msg), (msg) => request.Debug(msg)); query = new Uri(newResponse.RequestMessage.RequestUri.AbsoluteUri); request.SetHttpClient(newClient); if (newResponse.StatusCode == HttpStatusCode.Unauthorized) { // Calling the credential provider for a second time, using -IsRetry credentials = request.GetCredsFromCredProvider(query.AbsoluteUri.ToString(), request, true); newClient = PathUtility.GetHttpClientHelper(credentials.UserName, credentials.SecurePassword, null); newResponse = PathUtility.GetHttpResponse(newClient, query.AbsoluteUri, (() => request.IsCanceled), ((msg, num) => request.Verbose(Resources.Messages.RetryingDownload, msg, num)), (msg) => request.Verbose(msg), (msg) => request.Debug(msg)); query = new Uri(newResponse.RequestMessage.RequestUri.AbsoluteUri); request.SetHttpClient(newClient); if (newResponse.StatusCode == HttpStatusCode.Unauthorized) { request.WriteError(ErrorCategory.PermissionDenied, "ValidateUri", Resources.Messages.AccessPermissionDenied, query); return(null); } } } else { // other status code is wrong return(null); } } } else { query = new Uri(response.RequestMessage.RequestUri.AbsoluteUri); } IPackageRepository repo = PackageRepositoryFactory.Default.CreateRepository(new PackageRepositoryCreateParameters(query.AbsoluteUri, request, locationValid: true)); if (repo.ResourceProvider != null) { // If the query feed exists, it's a non-local repo // Check the query feed to make sure it's available // Optionally we could change this to check the packages feed for availability if (repo.ResourceProvider.QueryFeed == null || !repo.ResourceProvider.QueryFeed.IsAvailable(new RequestWrapper(request, credentials))) { return(null); } } return(query); }