Пример #1
0
        internal static ProgressTracker StartProgress(ProgressTracker parentTracker, string message, NuGetRequest request)
        {
            if (request == null)
            {
                return null;
            }

            // if parent tracker is null, use 0 for parent id, else use the progressid of parent tracker
            return new ProgressTracker(request.StartProgress(parentTracker == null ? 0 : parentTracker.ProgressID, message));
        }
Пример #2
0
        /// <summary>
        /// Download data from remote via uri query.
        /// </summary>
        /// <param name="fileName">A file to store the downloaded data.</param>
        /// <param name="query">Uri query</param>
        /// <param name="request">An object passed in from the PackageManagement platform that contains APIs that can be used to interact with it </param>   
        /// <param name="networkCredential">Credential to pass along to get httpclient</param>
        /// <param name="progressTracker">Utility class to help track progress</param>
        /// <returns></returns>
        internal static async Task<long> DownloadDataToFileAsync(string fileName, string query, NuGetRequest request,
            NetworkCredential networkCredential, ProgressTracker progressTracker)
        {
            request.Verbose(Messages.DownloadingPackage, query);

            var httpClient = request.Client;

            // try downloading for 3 times
            int remainingTry = 3;
            long totalDownloaded = 0;
            long totalBytesToReceive = 0;
            bool cleanUp = false;
            CancellationTokenSource cts = new CancellationTokenSource(); ;
            Stream input = null;
            Timer timer = null;
            FileStream output = null;
            object lockObject = new object();

            // function to perform cleanup
            Action cleanUpAction = () => {
                lock (lockObject)
                {
                    // if clean up is done before, don't need to do again
                    if (!cleanUp)
                    {
                        try
                        {
                            // dispose timer
                            if (timer != null)
                            {
                                timer.Change(Timeout.Infinite, Timeout.Infinite);
                                timer.Dispose();
                            }

                            // dispose cts token
                            if (cts != null)
                            {
                                cts.Cancel();
                                cts.Dispose();
                            }
                        }
                        catch { }

                        try
                        {
                            // dispose input and output stream
                            if (input != null)
                            {
                                input.Dispose();
                            }

                            // it is important that we dispose of the output here, otherwise we may not be able to delete the file
                            if (output != null)
                            {
                                output.Dispose();
                            }

                            // if the download didn't complete, log verbose message
                            if (totalBytesToReceive != totalDownloaded)
                            {
                                request.Verbose(string.Format(Resources.Messages.IncompleteDownload, totalDownloaded, totalBytesToReceive));
                            }

                            // if we couldn't download anything
                            if (totalDownloaded == 0 && File.Exists(fileName))
                            {
                                File.Delete(fileName);
                            }
                        }
                        catch { }

                        cleanUp = true;
                    }
                }
            };

            while (remainingTry > 0)
            {
                // if user cancel the request, no need to do anything
                if (request.IsCanceled)
                {
                    break;
                }

                input = null;
                output = null;
                totalDownloaded = 0;

                try
                {
                    // decrease try by 1
                    remainingTry -= 1;

                    // create new timer and cancellation token source
                    lock (lockObject)
                    {
                        // check every second to see whether request is cancelled
                        timer = new Timer(_ =>
                        {
                            if (request.IsCanceled)
                            {
                                cleanUpAction();
                            }
                        }, null, 500, 1000);

                        cts = new CancellationTokenSource();

                        cleanUp = false;
                    }

                    var response = await httpClient.GetAsync(query, HttpCompletionOption.ResponseHeadersRead, cts.Token);

                    if (response.Content != null && response.Content.Headers != null)
                    {
                        totalBytesToReceive = response.Content.Headers.ContentLength ?? 0;
                        // the total amount of bytes we need to download in megabytes
                        double totalBytesToReceiveMB = (totalBytesToReceive / 1024f) / 1024f;

                        // Read response asynchronously and write out a file
                        // The return value is for the caller to wait for the async operation to complete.
                        input = await response.Content.ReadAsStreamAsync();

                        // buffer size of 64 KB, this seems to be preferable buffer size, not too small and not too big
                        byte[] bytes = new byte[1024 * 64];
                        output = File.Open(fileName, FileMode.OpenOrCreate);

                        int current = 0;
                        double lastPercent = 0;

                        // here we read content that we got from the http response stream into the bytes array
                        current = await input.ReadAsync(bytes, 0, bytes.Length, cts.Token);

                        // report initial progress
                        request.Progress(progressTracker.ProgressID, progressTracker.StartPercent,
                            string.Format(CultureInfo.CurrentCulture, Resources.Messages.DownloadingProgress, 0, (totalBytesToReceive / 1024f) / 1024f));

                        while (current > 0)
                        {
                            totalDownloaded += current;

                            // here we write the bytes array content into the file
                            await output.WriteAsync(bytes, 0, current, cts.Token);

                            double percent = totalDownloaded * 1.0 / totalBytesToReceive;

                            // don't want to report too often (slow down performance)
                            if (percent > lastPercent + 0.1)
                            {
                                lastPercent = percent;
                                // percent between startProgress and endProgress
                                var progressPercent = progressTracker.ConvertPercentToProgress(percent);

                                // report the progress
                                request.Progress(progressTracker.ProgressID, (int)progressPercent,
                                    string.Format(CultureInfo.CurrentCulture, Resources.Messages.DownloadingProgress, (totalDownloaded / 1024f) / 1024f, totalBytesToReceiveMB));
                            }

                            // here we read content that we got from the http response stream into the bytes array
                            current = await input.ReadAsync(bytes, 0, bytes.Length, cts.Token);
                        }

                        // check that we download everything
                        if (totalDownloaded == totalBytesToReceive)
                        {
                            // report that we finished with the download
                            request.Progress(progressTracker.ProgressID, progressTracker.EndPercent,
                                string.Format(CultureInfo.CurrentCulture, Resources.Messages.DownloadingProgress, totalDownloaded, totalBytesToReceive));

                            request.Verbose(Messages.CompletedDownload, query);

                            break;
                        }

                        // otherwise, we have to retry again
                    }

                    // if request is canceled, don't retry
                    if (request.IsCanceled)
                    {
                        break;
                    }

                    request.Verbose(Resources.Messages.RetryingDownload, query, remainingTry);
                }
                catch (Exception ex)
                {
                    request.Verbose(ex.Message);
                    request.Debug(ex.StackTrace);
                    // if there is exception, we will retry too
                    request.Verbose(Resources.Messages.RetryingDownload, query, remainingTry);
                }
                finally
                {
                    cleanUpAction();
                }
            }

            return totalDownloaded;
        }
Пример #3
0
        /// <summary>
        /// Download a nuget package.
        /// </summary>
        /// <param name="packageName">Package name</param>
        /// <param name="version">Package version</param>
        /// <param name="destination">Destination location to store the downloaded package</param>
        /// <param name="queryUrl">Uri to query the package</param>
        /// <param name="request">An object passed in from the PackageManagement platform that contains APIs that can be used to interact with it </param>   
        /// <param name="pkgSource">source to download the package</param>
        /// <param name="progressTracker">Utility class to help track progress</param>
        /// 
        internal static bool DownloadPackage(string packageName, string version, string destination, string queryUrl, NuGetRequest request, PackageSource pkgSource, ProgressTracker progressTracker) 
        {
            try {                
                request.Verbose(string.Format(CultureInfo.InvariantCulture, "DownloadPackage' - name='{0}', version='{1}',destination='{2}', uri='{3}'", packageName, version, destination, queryUrl));

                if (new Uri(queryUrl).IsFile) {
                    throw new ArgumentException(Constants.Messages.UriSchemeNotSupported, queryUrl);
                }

                long result = 0;

                // Do not need to validate here again because the job is done by the httprepository that supplies the queryurl
                //Downloading the package
                //request.Verbose(httpquery);
                result = DownloadDataToFileAsync(destination, queryUrl, request, PathUtility.GetNetworkCredential(request.CredentialUsername, request.CredentialPassword), progressTracker).Result;                   

                if (result == 0 || !File.Exists(destination))
                {
                    request.Verbose(Messages.FailedDownloadPackage, packageName, queryUrl);
                    request.Warning(Constants.Messages.SourceLocationNotValid, queryUrl);
                    return false;
                } else {
                    request.Verbose(Messages.CompletedDownload, packageName);
                    return true;
                }
            } catch (Exception ex) {
                ex.Dump(request);
                request.Warning(Constants.Messages.PackageFailedInstallOrDownload, packageName, CultureInfo.CurrentCulture.TextInfo.ToLower(Constants.Download));
                throw;
            }
        }
Пример #4
0
        /// <summary>
        /// Download a package from a file repository that matches the given version and name and install it on the local system.
        /// </summary>
        /// <param name="packageName">Package name</param>
        /// <param name="version">Package version</param>
        /// <param name="request">An object passed in from the PackageManagement platform that contains APIs that can be used to interact with it </param>  
        /// <param name="source">Package source</param>
        /// <param name="sourceFilePath">File source path pointing to the package to be installed</param>
        /// <param name="progressTracker">progress tracker to help keep track of progressid, start and end of the progress</param>
        /// <returns>PackageItem object</returns>
        internal static PackageItem InstallPackageLocal(
            string packageName, 
            string version,
            NuGetRequest request, 
            PackageSource source,             
            string sourceFilePath,
            ProgressTracker progressTracker
            )
        {
            request.Debug(Messages.DebugInfoCallMethod, "NuGetClient", "InstallPackageLocal");

            string tempSourceFilePath = null;
            string tempSourceDirectory = null;

            string directoryToDeleteWhenFailed = String.Empty;
            bool needToDelete = false;

            try 
            {
                string destinationFilePath = request.Destination;
                request.Verbose(string.Format(CultureInfo.InvariantCulture, "InstallPackageLocal' - name='{0}', version='{1}',destination='{2}'", packageName, version, destinationFilePath));
                request.Debug(sourceFilePath);

                if (string.IsNullOrWhiteSpace(sourceFilePath))
                {
                    throw new ArgumentNullException(sourceFilePath);
                }

                if (!File.Exists(sourceFilePath)) {
                    throw new FileNotFoundException(sourceFilePath);
                }

                //Create the destination directory if it does not exist
                if (!Directory.Exists(destinationFilePath)) {
                    Directory.CreateDirectory(destinationFilePath);
                    directoryToDeleteWhenFailed = destinationFilePath;
                }

                //Make a temp folder in the user appdata temp directory 
                tempSourceFilePath = FileUtility.GetTempFileFullPath(fileExtension: NuGetConstant.PackageExtension);

                //Copy over the source file from  the folder repository to the temp folder
                File.Copy(sourceFilePath, tempSourceFilePath, true);

                request.Progress(progressTracker.ProgressID, progressTracker.StartPercent, string.Format(CultureInfo.CurrentCulture, Messages.Unzipping));
                //Unzip it
                tempSourceDirectory = PackageUtility.DecompressFile(tempSourceFilePath);

                //Get a package directory under the destination path to store the package
                string installedFolder = FileUtility.MakePackageDirectoryName(request.ExcludeVersion.Value, destinationFilePath, packageName, version);

                // if we did not set the directory before, then the destinationFilePath already exists, so we should not delete it
                if (string.IsNullOrWhiteSpace(directoryToDeleteWhenFailed))
                {
                    directoryToDeleteWhenFailed = installedFolder;
                }

                //File folder format of the Nuget packages looks like the following after installed:
                //Jquery.2.0.1
                //  - JQuery.2.0.1.nupkg
                //  - contents and other stuff

                // unzipping should take most of the time (assuming 70%)

                request.Progress(progressTracker.ProgressID, progressTracker.ConvertPercentToProgress(0.7), string.Format(CultureInfo.CurrentCulture, Messages.CopyUnzippedFiles, installedFolder));

                //Copy the unzipped files to under the package installed folder
                FileUtility.CopyDirectory(tempSourceDirectory, installedFolder, true);
                
                // copying should take another 15%
                // copy the nupkg file if it's not in
                var nupkgFilePath = Path.Combine(installedFolder, FileUtility.MakePackageFileName(request.ExcludeVersion.Value, packageName, version, NuGetConstant.PackageExtension));

                if (!File.Exists(nupkgFilePath))
                {
                    File.Copy(sourceFilePath, nupkgFilePath);
                }

                request.Progress(progressTracker.ProgressID, progressTracker.ConvertPercentToProgress(0.85), string.Format(CultureInfo.CurrentCulture, Messages.ReadingManifest));

                 //Read the package manifest and return the package object
                string nuspec = Path.Combine(installedFolder, packageName) + NuGetConstant.ManifestExtension;

                PackageBase package = PackageUtility.ProcessNuspec(nuspec);

                var pkgItem = new PackageItem {
                    Package = package,
                    PackageSource = source,
                    FastPath = request.MakeFastPath(source, package.Id, package.Version),
                    FullPath = installedFolder
                };

                // Delete the nuspec file
                //Get a package file path
                var nuspecFilePath = Path.Combine(installedFolder, packageName + NuGetConstant.ManifestExtension);

                if (File.Exists(nuspecFilePath))
                {
                    FileUtility.DeleteFile(nuspecFilePath, false);
                }

                request.Debug(Messages.DebugInfoReturnCall, "NuGetClient", "InstallPackageLocal");

                request.Progress(progressTracker.ProgressID, progressTracker.EndPercent, string.Format(CultureInfo.CurrentCulture, Messages.FinishInstalling, packageName));

                return pkgItem;

            } catch (Exception ex) {
                needToDelete = true;
                // the error will be package "packageName" failed to install because : "reason"
                ex.Dump(request);
                request.WriteError(ErrorCategory.InvalidResult, packageName, Resources.Messages.PackageFailedToInstallReason, packageName, ex.Message);
                throw;
            } finally {
                if (needToDelete && Directory.Exists(directoryToDeleteWhenFailed))
                {
                    FileUtility.DeleteDirectory(directoryToDeleteWhenFailed, true, isThrow: false);
                }

                FileUtility.DeleteFile(tempSourceFilePath, isThrow:false);
                FileUtility.DeleteDirectory(tempSourceDirectory, recursive: true, isThrow: false);
            }
        }
Пример #5
0
        /// <summary>
        /// Download a package that matches the given version and name and install it on the local system.
        /// </summary>
        /// <param name="packageName">Package name</param>
        /// <param name="version">Package version</param>
        /// <param name="request">An object passed in from the PackageManagement platform that contains APIs that can be used to interact with it </param>  
        /// <param name="source">Package source</param>
        /// <param name="queryUrl">Full uri</param>
        /// <param name="packageHash">the hash of the package</param>
        /// <param name="packageHashAlgorithm">the hash algorithm of the package</param>
        /// <param name="progressTracker">progress tracker to help keep track of progressid, start and end of the progress</param>
        /// <returns>PackageItem object</returns>
        internal static PackageItem InstallPackage(
            string packageName,
            string version,
            NuGetRequest request,
            PackageSource source,
            string queryUrl,
            string packageHash,
            string packageHashAlgorithm,
            ProgressTracker progressTracker
            ) 
        {
            request.Debug(Messages.DebugInfoCallMethod, "NuGetClient", "InstallPackage");

            //If the destination folder does not exists, create it
            string destinationPath = request.Destination;
            request.Verbose(string.Format(CultureInfo.InvariantCulture, "InstallPackage' - name='{0}', version='{1}',destination='{2}'", packageName, version, destinationPath));

            string directoryToDeleteWhenFailed = string.Empty;
            bool needToDelete = false;
            string installFullPath = string.Empty;

            try
            {
                if (!Directory.Exists(destinationPath)) {
                    Directory.CreateDirectory(destinationPath);
                    // delete the destinationPath later on if we fail to install and if destinationPath did not exist before
                    directoryToDeleteWhenFailed = destinationPath;
                }

                //Create a folder under the destination path to hold the package
                string installDir = FileUtility.MakePackageDirectoryName(request.ExcludeVersion.Value, destinationPath, packageName, version);

                if (!Directory.Exists(installDir)) {
                    Directory.CreateDirectory(installDir);

                    // if directoryToDeleteWhenFailed is null then the destinationPath already exists before so we should not delete it
                    if (String.IsNullOrWhiteSpace(directoryToDeleteWhenFailed))
                    {
                        directoryToDeleteWhenFailed = installDir;
                    }
                }

                //Get the package file name based on the version and id
                string fileName = FileUtility.MakePackageFileName(request.ExcludeVersion.Value, packageName, version, NuGetConstant.PackageExtension);

                installFullPath = Path.Combine(installDir, fileName);

                // we assume downloading takes 70% of the progress
                int endProgressDownloading = progressTracker.ConvertPercentToProgress(0.7);

                //download to fetch the package
                DownloadPackage(packageName, version, installFullPath, queryUrl, request, source, new ProgressTracker(progressTracker.ProgressID, progressTracker.StartPercent, endProgressDownloading));

                // check that we have the file
                if (!File.Exists(installFullPath))
                {
                    needToDelete = true;
                    // error message is package failed to be downloaded
                    request.WriteError(ErrorCategory.ResourceUnavailable, installFullPath, Constants.Messages.PackageFailedInstallOrDownload, packageName,
                        CultureInfo.CurrentCulture.TextInfo.ToLower(Constants.Download));
                    return null;
                }

                #region verify hash
                //we don't enable checking for hash here because it seems like nuget provider does not
                //checks that there is hash. Otherwise we don't carry out the install
                
                if (string.IsNullOrWhiteSpace(packageHash))
                {
                    // if no hash (for example, vsts feed, install the package but log verbose message)
                    request.Verbose(string.Format(CultureInfo.CurrentCulture, Resources.Messages.HashNotFound, packageName));
                    //parse the package
                    var pkgItem = InstallPackageLocal(packageName, version, request, source, installFullPath, new ProgressTracker(progressTracker.ProgressID, endProgressDownloading, progressTracker.EndPercent));
                    return pkgItem;
                }

                // Verify the hash
                using (FileStream stream = File.OpenRead(installFullPath))
                {
                    HashAlgorithm hashAlgorithm = null;

                    switch (packageHashAlgorithm == null ? string.Empty : packageHashAlgorithm.ToLowerInvariant())
                    {
                        case "sha256":
                            hashAlgorithm = SHA256.Create();
                            break;

                        case "md5":
                            hashAlgorithm = MD5.Create();
                            break;

                        case "sha512":
                        // Flows to default case

                        // default to sha512 algorithm
                        default:
                            hashAlgorithm = SHA512.Create();
                            break;
                    }

                    if (hashAlgorithm == null)
                    {
                        // delete the file downloaded. VIRUS!!!
                        needToDelete = true;
                        request.WriteError(ErrorCategory.SecurityError, packageHashAlgorithm, Constants.Messages.HashNotSupported, packageHashAlgorithm);
                        return null;
                    }

                    // compute the hash
                    byte[] computedHash = hashAlgorithm.ComputeHash(stream);

                    // convert the original hash we got from the feed
                    byte[] downloadedHash = Convert.FromBase64String(packageHash);

                    // if they are not equal, just issue out verbose because there is a current bug in backend
                    // where editing the published module will result in a package with a different hash than the one
                    // provided on the feed
                    if (!Enumerable.SequenceEqual(computedHash, downloadedHash))
                    {
                        // delete the file downloaded. VIRUS!!!
                        request.Verbose(Constants.Messages.HashNotMatch, packageName);
                    }

                    //parse the package
                    var pkgItem = InstallPackageLocal(packageName, version, request, source, installFullPath, new ProgressTracker(progressTracker.ProgressID, endProgressDownloading, progressTracker.EndPercent));
                    return pkgItem;
                }

                #endregion

            }
            catch (Exception ex)
            {
                // the error will be package "packageName" failed to install because : "reason"
                ex.Dump(request);
                request.WriteError(ErrorCategory.InvalidResult, packageName, Resources.Messages.PackageFailedToInstallReason, packageName, ex.Message);
                needToDelete = true;
            }
            finally
            {
                if (needToDelete)
                {
                    // if the directory exists just delete it because it will contains the file as well
                    if (!String.IsNullOrWhiteSpace(directoryToDeleteWhenFailed) && Directory.Exists(directoryToDeleteWhenFailed))
                    {
                        try
                        {
                            FileUtility.DeleteDirectory(directoryToDeleteWhenFailed, true, isThrow: false);
                        }
                        catch { }
                    }

                    // if for some reason, we can't delete the directory or if we don't need to delete the directory
                    // then we have to delete installFullPath
                    if (File.Exists(installFullPath))
                    {
                        FileUtility.DeleteFile(installFullPath, isThrow: false);
                    }
                }
            }

            return null;
        }
Пример #6
0
        /// <summary>
        /// Download a single package to destination without checking for dependencies
        /// </summary>
        /// <param name="pkgItem"></param>
        /// <param name="progressTracker"></param>
        /// <param name="request"></param>
        /// <param name="destLocation"></param>
        /// <returns></returns>
        internal static bool DownloadSinglePackage(PackageItem pkgItem, NuGetRequest request, string destLocation, ProgressTracker progressTracker)
        {
            if (string.IsNullOrWhiteSpace(pkgItem.PackageFilename) || pkgItem.PackageSource == null || pkgItem.PackageSource.Location == null
            || (pkgItem.PackageSource.IsSourceAFile && pkgItem.Package == null))
            {
                request.WriteError(ErrorCategory.ObjectNotFound, pkgItem.Id, Constants.Messages.UnableToResolvePackage, pkgItem.Id);
                return false;
            }

            // this is if the user says -force
            bool force = request.GetOptionValue("Force") != null;

            // combine the path and the file name
            destLocation = Path.Combine(destLocation, pkgItem.PackageFilename);

            // if the file already exists
            if (File.Exists(destLocation))
            {
                // if no force, just return
                if (!force)
                {
                    request.Verbose(Constants.Messages.SkippedDownloadedPackage, pkgItem.Id);
                    request.YieldPackage(pkgItem, pkgItem.PackageSource.Name);
                    return true;
                }

                // here we know it is forced, so delete
                FileUtility.DeleteFile(destLocation, isThrow: false);

                // if after we try delete, it is still there, tells the user we can't perform the action
                if (File.Exists(destLocation))
                {
                    request.WriteError(ErrorCategory.ResourceUnavailable, destLocation, Constants.Messages.UnableToOverwriteExistingFile, destLocation);
                    return false;
                }
            }

            bool downloadSuccessful = false;

            try
            {
                // if no repository, we can't do anything
                if (pkgItem.PackageSource.Repository == null)
                {
                    return false;
                }

                if (pkgItem.PackageSource.Repository.IsFile)
                {
                    using (var input = File.OpenRead(pkgItem.Package.FullFilePath))
                    {
                        using (var output = new FileStream(destLocation, FileMode.Create, FileAccess.Write, FileShare.Read))
                        {
                            input.CopyTo(output);
                        }
                    }
                }
                else
                {
                    //V2 download package protocol:
                    //sample url: http://www.nuget.org/api/v2/package/jQuery/2.1.3
                    string append = String.Format(CultureInfo.InvariantCulture, "/package/{0}/{1}", pkgItem.Id, pkgItem.Version);
                    string httpquery = PathUtility.UriCombine(pkgItem.PackageSource.Repository.Source, append);

                    downloadSuccessful = NuGetClient.DownloadPackage(pkgItem.Id, pkgItem.Version, destLocation,
                        string.IsNullOrWhiteSpace(pkgItem.Package.ContentSrcUrl) ? httpquery : pkgItem.Package.ContentSrcUrl, request, pkgItem.PackageSource, progressTracker);
                }
            }
            catch (Exception ex)
            {
                ex.Dump(request);
                return false;
            }

            if (downloadSuccessful)
            {
                request.Verbose(Resources.Messages.SuccessfullyDownloaded, pkgItem.Id);
                // provide the directory we save to to yieldpackage
                request.YieldPackage(pkgItem, pkgItem.PackageSource.Name, Path.GetDirectoryName(destLocation));
                return true;
            }

            return false;
        }
Пример #7
0
        /// <summary>
        /// Install a single package without checking for dependencies
        /// </summary>
        /// <param name="pkgItem"></param>
        /// <param name="request"></param>
        /// <param name="progressTracker"></param>
        /// <returns></returns>
        internal static bool InstallSinglePackage(PackageItem pkgItem, NuGetRequest request, ProgressTracker progressTracker)
        {
            PackageItem packageToBeInstalled;

            if (pkgItem == null || pkgItem.PackageSource == null || pkgItem.PackageSource.Repository == null)
            {
                return false;
            }

            // If the source location exists as a directory then we try to get the file location and provide to the packagelocal
            if (Directory.Exists(pkgItem.PackageSource.Location))
            {
                var fileLocation = pkgItem.PackageSource.Repository.FindPackage(pkgItem.Id, new SemanticVersion(pkgItem.Version), request).FullFilePath;
                packageToBeInstalled = NuGetClient.InstallPackageLocal(pkgItem.Id, pkgItem.Version, request, pkgItem.PackageSource, fileLocation, progressTracker);
            }
            else
            {             
                //V2 download package protocol:
                //sample url: http://www.nuget.org/api/v2/package/jQuery/2.1.3
                string append = String.Format(CultureInfo.InvariantCulture, "/package/{0}/{1}", pkgItem.Id, pkgItem.Version);
                string httpquery = PathUtility.UriCombine(pkgItem.PackageSource.Repository.Source, append);

                // wait for the result from installpackage
                packageToBeInstalled = NuGetClient.InstallPackage(pkgItem.Id, pkgItem.Version, request, pkgItem.PackageSource,
                    string.IsNullOrWhiteSpace(pkgItem.Package.ContentSrcUrl) ? httpquery : pkgItem.Package.ContentSrcUrl,
                    pkgItem.Package.PackageHash, pkgItem.Package.PackageHashAlgorithm, progressTracker);
            }

            // Package is installed successfully
            if (packageToBeInstalled != null)
            {
                // if this is a http repository, return metadata from online
                if (!pkgItem.PackageSource.Repository.IsFile)
                {
                    request.YieldPackage(pkgItem, packageToBeInstalled.PackageSource.Name, packageToBeInstalled.FullPath);
                }
                else
                {
                    request.YieldPackage(packageToBeInstalled, packageToBeInstalled.PackageSource.Name, packageToBeInstalled.FullPath);
                }

                request.Debug(Messages.DebugInfoReturnCall, "NuGetClient", "InstallSinglePackage");
                return true;
            }

            return false;
        }