private async Task<string> Download(Uri remoteLocation, string localFilename, bool showProgress, Request request, int pid) { var httpClient = new HttpClient(); // Apparently, places like Codeplex know to let this thru! httpClient.DefaultRequestHeaders.Add("user-agent", "chocolatey command line"); httpClient.DefaultRequestHeaders.ExpectContinue = false; long totalBytesToReceive = 0L; HttpResponseMessage response = await httpClient.GetAsync(remoteLocation, HttpCompletionOption.ResponseHeadersRead); if (!response.IsSuccessStatusCode) { return null; } if (response.Content != null && response.Content.Headers != null) { totalBytesToReceive = response.Content.Headers.ContentLength ?? 0; } try { Stream input = await response.Content.ReadAsStreamAsync(); byte[] bytes = new byte[1024 * 4]; FileStream output = File.Open(localFilename, FileMode.OpenOrCreate); long totalDownloaded = 0; int current = 0; int lastPercent = 0; current = await input.ReadAsync(bytes, 0, bytes.Length); while (current > 0) { totalDownloaded += current; int percent = (int)((totalDownloaded * 100) / totalBytesToReceive); await output.WriteAsync(bytes, 0, current); if (showProgress) { if (percent > lastPercent) { lastPercent = percent; request.Progress(pid, (int)percent, "To {0}", localFilename); } } current = await input.ReadAsync(bytes, 0, bytes.Length); } input.Dispose(); output.Dispose(); } catch (Exception) { localFilename = null; } return localFilename; }
public string DownloadFile(Uri remoteLocation, string localFilename, int timeoutMilliseconds, bool showProgress, Request request) { if (request == null) { throw new ArgumentNullException("request"); } if (remoteLocation == null) { throw new ArgumentNullException("remoteLocation"); } request.Debug("Calling 'WebDownloader::DownloadFile' '{0}','{1}','{2}','{3}'", remoteLocation, localFilename, timeoutMilliseconds, showProgress); if (remoteLocation.Scheme.ToLowerInvariant() != "http" && remoteLocation.Scheme.ToLowerInvariant() != "https" && remoteLocation.Scheme.ToLowerInvariant() != "ftp") { request.Error(ErrorCategory.InvalidResult, remoteLocation.ToString(), Constants.Messages.SchemeNotSupported, remoteLocation.Scheme); return null; } if (localFilename == null) { localFilename = "downloadedFile.tmp".GenerateTemporaryFilename(); } localFilename = Path.GetFullPath(localFilename); // did the caller pass us a directory name? if (Directory.Exists(localFilename)) { localFilename = Path.Combine(localFilename, "downloadedFile.tmp"); } // make sure that the parent folder is created first. var folder = Path.GetDirectoryName(localFilename); if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } // clobber an existing file if it's already there. // todo: in the future, we could check the md5 of the file and if the remote server supports it // todo: we could skip the download. if (File.Exists(localFilename)) { localFilename.TryHardToDelete(); } // setup the progress tracker if the caller wanted one. int pid = 0; if (showProgress) { pid = request.StartProgress(0, "Downloading '{0}'", remoteLocation); } #if CORECLR var task = Download(remoteLocation, localFilename, showProgress, request, pid); task.Wait(timeoutMilliseconds); if (!task.IsCompleted) { request.Warning(Constants.Status.TimedOut); request.Debug("Timed out downloading '{0}'", remoteLocation.AbsoluteUri); } #else var webClient = new WebClient(); webClient.Headers.Add("user-agent", "chocolatey command line"); var done = new ManualResetEvent(false); webClient.DownloadFileCompleted += (sender, args) => { if (args.Cancelled || args.Error != null) { localFilename = null; } done.Set(); }; var lastPercent = 0; if (showProgress) { webClient.DownloadProgressChanged += (sender, args) => { // Progress(requestObject, 2, (int)percent, "Downloading {0} of {1} bytes", args.BytesReceived, args.TotalBytesToReceive); var percent = (int)((args.BytesReceived*100)/args.TotalBytesToReceive); if (percent > lastPercent) { lastPercent = percent; request.Progress(pid, (int)((args.BytesReceived*100)/args.TotalBytesToReceive), "To {0}", localFilename); } }; } // start the download webClient.DownloadFileAsync(remoteLocation, localFilename); // wait for the completion if (timeoutMilliseconds > 0) { if (!done.WaitOne(timeoutMilliseconds)) { webClient.CancelAsync(); request.Warning(Constants.Status.TimedOut); request.Debug("Timed out downloading '{0}'", remoteLocation.AbsoluteUri); return null; } } else { // wait until it completes or fails on it's own done.WaitOne(); } #endif // if we don't have the file by this point, we've failed. if (localFilename == null || !File.Exists(localFilename)) { request.CompleteProgress(pid, false); request.Error(ErrorCategory.InvalidResult, remoteLocation.ToString(), Constants.Messages.UnableToDownload, remoteLocation.ToString(), localFilename); return null; } if (showProgress) { request.CompleteProgress(pid, true); } return localFilename; }
private async Task<string> Download(Uri remoteLocation, string localFilename, bool showProgress, Request request, int pid) { var clientHandler = new HttpClientHandler(); clientHandler.UseDefaultCredentials = true; // if user supplies web proxy, use that if (request.WebProxy != null) { clientHandler.Proxy = request.WebProxy; } var httpClient = new HttpClient(clientHandler); request.Debug("Calling httpclient with remotelocation {0}", remoteLocation.AbsoluteUri); // Mozilla/5.0 is the general token that says the browser is Mozilla compatible, and is common to almost every browser today. httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 PackageManagement"); httpClient.DefaultRequestHeaders.ExpectContinue = false; long totalBytesToReceive = 0L; HttpResponseMessage response = await httpClient.GetAsync(remoteLocation, HttpCompletionOption.ResponseHeadersRead); if (!response.IsSuccessStatusCode) { return null; } if (response.Content != null && response.Content.Headers != null) { totalBytesToReceive = response.Content.Headers.ContentLength ?? 0; } try { Stream input = await response.Content.ReadAsStreamAsync(); byte[] bytes = new byte[1024 * 4]; FileStream output = File.Open(localFilename, FileMode.OpenOrCreate); long totalDownloaded = 0; int current = 0; int lastPercent = 0; current = await input.ReadAsync(bytes, 0, bytes.Length); while (current > 0) { totalDownloaded += current; await output.WriteAsync(bytes, 0, current); if (showProgress && totalBytesToReceive != 0) { int percent = (int)((totalDownloaded * 100) / totalBytesToReceive); if (percent > lastPercent) { lastPercent = percent; request.Progress(pid, (int)percent, "To {0}", localFilename); } } current = await input.ReadAsync(bytes, 0, bytes.Length); } input.Dispose(); output.Dispose(); } catch (Exception e) { request.Debug(e.Message); localFilename = null; } return localFilename; }