From c4b6ba603810c65af83fb7b1ff3868c587f21978 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Thu, 14 Jan 2021 18:29:14 +0000 Subject: [PATCH 01/18] Invoke-WebRequest: Display downloaded bytes in human readable format and display total expected download size --- .../Common/WebResponseObject.Common.cs | 2 +- .../InvokeWebRequestCommand.CoreClr.cs | 3 +- .../utility/WebCmdlet/StreamHelper.cs | 42 ++++++++++++++++--- .../resources/WebCmdletStrings.resx | 4 +- test/xUnit/csharp/test_Utils.cs | 15 +++++++ 5 files changed, 56 insertions(+), 10 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs index 98e7c397e45..158d7cfa415 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs @@ -207,7 +207,7 @@ private void SetResponse(HttpResponseMessage response, Stream contentStream) } int initialCapacity = (int)Math.Min(contentLength, StreamHelper.DefaultReadBuffer); - _rawContentStream = new WebResponseContentMemoryStream(st, initialCapacity, null); + _rawContentStream = new WebResponseContentMemoryStream(st, initialCapacity, null, response.Content.Headers.ContentLength.Value); } // set the position of the content stream to the beginning _rawContentStream.Position = 0; diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs index dafcf3b4295..cd31665555e 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs @@ -37,7 +37,8 @@ internal override void ProcessResponse(HttpResponseMessage response) if (ShouldWriteToPipeline) { // creating a MemoryStream wrapper to response stream here to support IsStopping. - responseStream = new WebResponseContentMemoryStream(responseStream, StreamHelper.ChunkSize, this); + responseStream = new WebResponseContentMemoryStream(responseStream, StreamHelper.ChunkSize, this, + response.Content.Headers.ContentLength.Value); WebResponseObject ro = WebResponseObjectFactory.GetResponseObject(response, responseStream, this.Context); ro.RelationLink = _relationLink; WriteObject(ro); diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs index 43b625311b9..510ff8d0ca4 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs @@ -12,6 +12,8 @@ using System.Threading; using System.Threading.Tasks; +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("powershell-tests,PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] + namespace Microsoft.PowerShell.Commands { /// @@ -24,6 +26,7 @@ internal class WebResponseContentMemoryStream : MemoryStream { #region Data + private long? _contentLength; private readonly Stream _originalStreamToProxy; private bool _isInitialized = false; private readonly Cmdlet _ownerCmdlet; @@ -37,9 +40,11 @@ internal class WebResponseContentMemoryStream : MemoryStream /// /// /// Owner cmdlet if any. - internal WebResponseContentMemoryStream(Stream stream, int initialCapacity, Cmdlet cmdlet) + /// Expected download size in Bytes. + internal WebResponseContentMemoryStream(Stream stream, int initialCapacity, Cmdlet cmdlet, long? contentLength) : base(initialCapacity) { + this._contentLength = contentLength; _originalStreamToProxy = stream; _ownerCmdlet = cmdlet; } @@ -225,7 +230,13 @@ private void Initialize() { if (_ownerCmdlet != null) { - record.StatusDescription = StringUtil.Format(WebCmdletStrings.ReadResponseProgressStatus, totalLength); + record.StatusDescription = StringUtil.Format(WebCmdletStrings.ReadResponseProgressStatus, + DisplayHumanReadableFileSize(totalLength), + DisplayHumanReadableFileSize(_contentLength == null ? 0 : (long)_contentLength)); + if (_contentLength != null && _contentLength > 0) + { + record.PercentComplete = (int)(totalLength * 100 / (long)_contentLength); + } _ownerCmdlet.WriteProgress(record); if (_ownerCmdlet.IsStopping) @@ -259,6 +270,25 @@ private void Initialize() throw; } } + + private enum FileSizeUnit + { + Byte, KB, MB, GB, TB, PB, EB + } + + internal static string DisplayHumanReadableFileSize(long bytes) + { + if (bytes <= 0) + { + return $"0 {FileSizeUnit.Byte}"; + } + + var fileSizeUnit = (FileSizeUnit)(Math.Log10(bytes) / 3); + double value = bytes / (double)Math.Pow(1024, (long)fileSizeUnit); + var significantDigits = (int)fileSizeUnit; + var format = "0." + new String('0', sPowignificantDigits); + return value.ToString(format) + $" {fileSizeUnit}"; + } } internal static class StreamHelper @@ -285,7 +315,7 @@ internal static void WriteToStream(Stream input, Stream output, PSCmdlet cmdlet, Task copyTask = input.CopyToAsync(output, cancellationToken); - ProgressRecord record = new( + ProgressRecord record = new ProgressRecord( ActivityId, WebCmdletStrings.WriteRequestProgressActivity, WebCmdletStrings.WriteRequestProgressStatus); @@ -323,13 +353,13 @@ internal static void SaveStreamToFile(Stream stream, string filePath, PSCmdlet c { // If the web cmdlet should resume, append the file instead of overwriting. FileMode fileMode = cmdlet is WebRequestPSCmdlet webCmdlet && webCmdlet.ShouldResume ? FileMode.Append : FileMode.Create; - using FileStream output = new(filePath, fileMode, FileAccess.Write, FileShare.Read); + using FileStream output = new FileStream(filePath, fileMode, FileAccess.Write, FileShare.Read); WriteToStream(stream, output, cmdlet, cancellationToken); } private static string StreamToString(Stream stream, Encoding encoding) { - StringBuilder result = new(capacity: ChunkSize); + StringBuilder result = new StringBuilder(capacity: ChunkSize); Decoder decoder = encoding.GetDecoder(); int useBufferSize = 64; @@ -411,7 +441,7 @@ internal static bool TryGetEncoding(string characterSet, out Encoding encoding) return result; } - private static readonly Regex s_metaexp = new( + private static readonly Regex s_metaexp = new Regex( @"<]*charset\s*=\s*[""'\n]?(?[A-Za-z].[^\s""'\n<>]*)[\s""'\n>]", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase ); diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx index fc1d25ac42f..a5ee54f36e3 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx @@ -199,13 +199,13 @@ The cmdlet cannot run because the following parameter is missing: Proxy. Provide a valid proxy URI for the Proxy parameter when using the ProxyCredential or ProxyUseDefaultCredentials parameters, then retry. - Reading web response completed. (Number of bytes read: {0}) + Reading web response completed. (Downloaded: {0}) Reading web response - Reading response stream... (Number of bytes read: {0}) + Reading response stream... (Downloaded: {0} of {1}) The operation has timed out. diff --git a/test/xUnit/csharp/test_Utils.cs b/test/xUnit/csharp/test_Utils.cs index ea45ce533d6..19be09c31fa 100644 --- a/test/xUnit/csharp/test_Utils.cs +++ b/test/xUnit/csharp/test_Utils.cs @@ -22,6 +22,21 @@ public static void TestIsWinPEHost() Assert.False(Utils.IsWinPEHost()); } + [Theory] + [InlineData(long.MinValue, "0 Byte")] + [InlineData(-1, "0 Byte")] + [InlineData(0, "0 Byte")] + [InlineData(1, "1 Byte")] + [InlineData(1024, "1.0 KB")] + [InlineData(3000, "2.9 KB")] + [InlineData(1024 * 1024, "1.00 MB")] + [InlineData(1024 * 1024 * 1024, "1.000 GB")] + [InlineData(long.MaxValue, "8.000000 EB")] + public static void DisplayHumanReadableFileSize(long bytes, string expected) + { + Assert.Equal(expected, WebResponseContentMemoryStream.DisplayHumanReadableFileSize(bytes)); + } + [Fact] public static void TestHistoryStack() { From f01fa764ec115c1d4446b4d6701528a9cfea87cc Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Thu, 14 Jan 2021 19:30:04 +0000 Subject: [PATCH 02/18] fix typo --- .../commands/utility/WebCmdlet/StreamHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs index 510ff8d0ca4..508eba70cac 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs @@ -286,7 +286,7 @@ internal static string DisplayHumanReadableFileSize(long bytes) var fileSizeUnit = (FileSizeUnit)(Math.Log10(bytes) / 3); double value = bytes / (double)Math.Pow(1024, (long)fileSizeUnit); var significantDigits = (int)fileSizeUnit; - var format = "0." + new String('0', sPowignificantDigits); + var format = "0." + new String('0', significantDigits); return value.ToString(format) + $" {fileSizeUnit}"; } } From 016c017d788e17626d53d741feac3a5fb8b9952c Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Thu, 14 Jan 2021 19:51:44 +0000 Subject: [PATCH 03/18] simplify diff and address style issues --- .../CoreCLR/InvokeWebRequestCommand.CoreClr.cs | 5 ++++- .../commands/utility/WebCmdlet/StreamHelper.cs | 16 +++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs index cd31665555e..47a3c89aff8 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs @@ -37,7 +37,10 @@ internal override void ProcessResponse(HttpResponseMessage response) if (ShouldWriteToPipeline) { // creating a MemoryStream wrapper to response stream here to support IsStopping. - responseStream = new WebResponseContentMemoryStream(responseStream, StreamHelper.ChunkSize, this, + responseStream = new WebResponseContentMemoryStream( + responseStream, + StreamHelper.ChunkSize, + this, response.Content.Headers.ContentLength.Value); WebResponseObject ro = WebResponseObjectFactory.GetResponseObject(response, responseStream, this.Context); ro.RelationLink = _relationLink; diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs index 508eba70cac..2720a4effb1 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs @@ -26,7 +26,7 @@ internal class WebResponseContentMemoryStream : MemoryStream { #region Data - private long? _contentLength; + private readonly long? _contentLength; private readonly Stream _originalStreamToProxy; private bool _isInitialized = false; private readonly Cmdlet _ownerCmdlet; @@ -230,13 +230,15 @@ private void Initialize() { if (_ownerCmdlet != null) { - record.StatusDescription = StringUtil.Format(WebCmdletStrings.ReadResponseProgressStatus, + record.StatusDescription = StringUtil.Format( + WebCmdletStrings.ReadResponseProgressStatus, DisplayHumanReadableFileSize(totalLength), DisplayHumanReadableFileSize(_contentLength == null ? 0 : (long)_contentLength)); if (_contentLength != null && _contentLength > 0) { record.PercentComplete = (int)(totalLength * 100 / (long)_contentLength); } + _ownerCmdlet.WriteProgress(record); if (_ownerCmdlet.IsStopping) @@ -286,7 +288,7 @@ internal static string DisplayHumanReadableFileSize(long bytes) var fileSizeUnit = (FileSizeUnit)(Math.Log10(bytes) / 3); double value = bytes / (double)Math.Pow(1024, (long)fileSizeUnit); var significantDigits = (int)fileSizeUnit; - var format = "0." + new String('0', significantDigits); + var format = "0." + new string('0', significantDigits); return value.ToString(format) + $" {fileSizeUnit}"; } } @@ -315,7 +317,7 @@ internal static void WriteToStream(Stream input, Stream output, PSCmdlet cmdlet, Task copyTask = input.CopyToAsync(output, cancellationToken); - ProgressRecord record = new ProgressRecord( + ProgressRecord record = new( ActivityId, WebCmdletStrings.WriteRequestProgressActivity, WebCmdletStrings.WriteRequestProgressStatus); @@ -353,13 +355,13 @@ internal static void SaveStreamToFile(Stream stream, string filePath, PSCmdlet c { // If the web cmdlet should resume, append the file instead of overwriting. FileMode fileMode = cmdlet is WebRequestPSCmdlet webCmdlet && webCmdlet.ShouldResume ? FileMode.Append : FileMode.Create; - using FileStream output = new FileStream(filePath, fileMode, FileAccess.Write, FileShare.Read); + using FileStream output = new(filePath, fileMode, FileAccess.Write, FileShare.Read); WriteToStream(stream, output, cmdlet, cancellationToken); } private static string StreamToString(Stream stream, Encoding encoding) { - StringBuilder result = new StringBuilder(capacity: ChunkSize); + StringBuilder result = new(capacity: ChunkSize); Decoder decoder = encoding.GetDecoder(); int useBufferSize = 64; @@ -441,7 +443,7 @@ internal static bool TryGetEncoding(string characterSet, out Encoding encoding) return result; } - private static readonly Regex s_metaexp = new Regex( + private static readonly Regex s_metaexp = new( @"<]*charset\s*=\s*[""'\n]?(?[A-Za-z].[^\s""'\n<>]*)[\s""'\n>]", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase ); From 7cf8c3dfb55a4595deb8e90e0659dcfe92e77e8d Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Thu, 14 Jan 2021 22:12:04 +0000 Subject: [PATCH 04/18] Fix NullReferenceExceptions that caused test failures --- .../utility/WebCmdlet/Common/WebResponseObject.Common.cs | 2 +- .../WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs index 158d7cfa415..73c0cf5a2c3 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs @@ -207,7 +207,7 @@ private void SetResponse(HttpResponseMessage response, Stream contentStream) } int initialCapacity = (int)Math.Min(contentLength, StreamHelper.DefaultReadBuffer); - _rawContentStream = new WebResponseContentMemoryStream(st, initialCapacity, null, response.Content.Headers.ContentLength.Value); + _rawContentStream = new WebResponseContentMemoryStream(st, initialCapacity, null, response.Content.Headers.ContentLength.GetValueOrDefault()); } // set the position of the content stream to the beginning _rawContentStream.Position = 0; diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs index 47a3c89aff8..9e0727b291d 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs @@ -41,7 +41,7 @@ internal override void ProcessResponse(HttpResponseMessage response) responseStream, StreamHelper.ChunkSize, this, - response.Content.Headers.ContentLength.Value); + response.Content.Headers.ContentLength.GetValueOrDefault()); WebResponseObject ro = WebResponseObjectFactory.GetResponseObject(response, responseStream, this.Context); ro.RelationLink = _relationLink; WriteObject(ro); From 58eab3688b038009e9503223665db0c98c794129 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Fri, 15 Jan 2021 20:31:43 +0000 Subject: [PATCH 05/18] address PR comment around named parameter and tweak message --- .../utility/WebCmdlet/Common/WebResponseObject.Common.cs | 2 +- .../resources/WebCmdletStrings.resx | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs index 73c0cf5a2c3..2d4057edfa5 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs @@ -207,7 +207,7 @@ private void SetResponse(HttpResponseMessage response, Stream contentStream) } int initialCapacity = (int)Math.Min(contentLength, StreamHelper.DefaultReadBuffer); - _rawContentStream = new WebResponseContentMemoryStream(st, initialCapacity, null, response.Content.Headers.ContentLength.GetValueOrDefault()); + _rawContentStream = new WebResponseContentMemoryStream(st, initialCapacity, cmdlet:null, response.Content.Headers.ContentLength.GetValueOrDefault()); } // set the position of the content stream to the beginning _rawContentStream.Position = 0; diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx index a5ee54f36e3..84565510203 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx @@ -199,13 +199,13 @@ The cmdlet cannot run because the following parameter is missing: Proxy. Provide a valid proxy URI for the Proxy parameter when using the ProxyCredential or ProxyUseDefaultCredentials parameters, then retry. - Reading web response completed. (Downloaded: {0}) + Reading web response stream completed. Downloaded: {0} - Reading web response + Reading web response stream - Reading response stream... (Downloaded: {0} of {1}) + Downloaded: {0} of {1} The operation has timed out. From 75578732f516c3d2171bf0320f0b0476fac98455 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Fri, 15 Jan 2021 20:33:31 +0000 Subject: [PATCH 06/18] fix spacing issue of codefactor --- .../utility/WebCmdlet/Common/WebResponseObject.Common.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs index 2d4057edfa5..ed6c02a65c7 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebResponseObject.Common.cs @@ -207,7 +207,7 @@ private void SetResponse(HttpResponseMessage response, Stream contentStream) } int initialCapacity = (int)Math.Min(contentLength, StreamHelper.DefaultReadBuffer); - _rawContentStream = new WebResponseContentMemoryStream(st, initialCapacity, cmdlet:null, response.Content.Headers.ContentLength.GetValueOrDefault()); + _rawContentStream = new WebResponseContentMemoryStream(st, initialCapacity, cmdlet: null, response.Content.Headers.ContentLength.GetValueOrDefault()); } // set the position of the content stream to the beginning _rawContentStream.Position = 0; From e7a381910fed706fad49d7ed295b36d632d9c210 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Fri, 15 Jan 2021 21:07:48 +0000 Subject: [PATCH 07/18] Apply the same pattern also to the code path that saves a stream to a file --- .../Common/InvokeRestMethodCommand.Common.cs | 2 +- .../InvokeWebRequestCommand.CoreClr.cs | 2 +- .../utility/WebCmdlet/StreamHelper.cs | 20 ++++++++++++++----- .../resources/WebCmdletStrings.resx | 2 +- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/InvokeRestMethodCommand.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/InvokeRestMethodCommand.Common.cs index 235aaf82773..91850d5113e 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/InvokeRestMethodCommand.Common.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/InvokeRestMethodCommand.Common.cs @@ -458,7 +458,7 @@ internal override void ProcessResponse(HttpResponseMessage response) } else if (ShouldSaveToOutFile) { - StreamHelper.SaveStreamToFile(baseResponseStream, QualifiedOutFile, this, _cancelToken.Token); + StreamHelper.SaveStreamToFile(baseResponseStream, QualifiedOutFile, this, response.Content.Headers.ContentLength.GetValueOrDefault(), _cancelToken.Token); } if (!string.IsNullOrEmpty(StatusCodeVariable)) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs index 9e0727b291d..e03fca5a7d6 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/InvokeWebRequestCommand.CoreClr.cs @@ -55,7 +55,7 @@ internal override void ProcessResponse(HttpResponseMessage response) if (ShouldSaveToOutFile) { - StreamHelper.SaveStreamToFile(responseStream, QualifiedOutFile, this, _cancelToken.Token); + StreamHelper.SaveStreamToFile(responseStream, QualifiedOutFile, this, response.Content.Headers.ContentLength.GetValueOrDefault(), _cancelToken.Token); } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs index 2720a4effb1..b1b1d55a443 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs @@ -233,7 +233,7 @@ private void Initialize() record.StatusDescription = StringUtil.Format( WebCmdletStrings.ReadResponseProgressStatus, DisplayHumanReadableFileSize(totalLength), - DisplayHumanReadableFileSize(_contentLength == null ? 0 : (long)_contentLength)); + DisplayHumanReadableFileSize(_contentLength is null ? 0 : (long)_contentLength)); if (_contentLength != null && _contentLength > 0) { record.PercentComplete = (int)(totalLength * 100 / (long)_contentLength); @@ -308,7 +308,7 @@ internal static class StreamHelper #region Static Methods - internal static void WriteToStream(Stream input, Stream output, PSCmdlet cmdlet, CancellationToken cancellationToken) + internal static void WriteToStream(Stream input, Stream output, PSCmdlet cmdlet, long? contentLength, CancellationToken cancellationToken) { if (cmdlet == null) { @@ -325,7 +325,16 @@ internal static void WriteToStream(Stream input, Stream output, PSCmdlet cmdlet, { do { - record.StatusDescription = StringUtil.Format(WebCmdletStrings.WriteRequestProgressStatus, output.Position); + record.StatusDescription = StringUtil.Format( + WebCmdletStrings.WriteRequestProgressStatus, + WebResponseContentMemoryStream.DisplayHumanReadableFileSize(output.Position), + WebResponseContentMemoryStream.DisplayHumanReadableFileSize(contentLength is null ? 0 : (long)contentLength)); + + if (contentLength != null && contentLength > 0) + { + record.PercentComplete = (int)(output.Position * 100 / (long)contentLength); + } + cmdlet.WriteProgress(record); Task.Delay(1000).Wait(cancellationToken); @@ -350,13 +359,14 @@ internal static void WriteToStream(Stream input, Stream output, PSCmdlet cmdlet, /// Input stream. /// Output file name. /// Current cmdlet (Invoke-WebRequest or Invoke-RestMethod). + /// Expected download size in Bytes. /// CancellationToken to track the cmdlet cancellation. - internal static void SaveStreamToFile(Stream stream, string filePath, PSCmdlet cmdlet, CancellationToken cancellationToken) + internal static void SaveStreamToFile(Stream stream, string filePath, PSCmdlet cmdlet, long? contentLength, CancellationToken cancellationToken) { // If the web cmdlet should resume, append the file instead of overwriting. FileMode fileMode = cmdlet is WebRequestPSCmdlet webCmdlet && webCmdlet.ShouldResume ? FileMode.Append : FileMode.Create; using FileStream output = new(filePath, fileMode, FileAccess.Write, FileShare.Read); - WriteToStream(stream, output, cmdlet, cancellationToken); + WriteToStream(stream, output, cmdlet, contentLength, cancellationToken); } private static string StreamToString(Stream stream, Encoding encoding) diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx index 84565510203..0336d7c1c6a 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx @@ -223,7 +223,7 @@ Web request status - Number of bytes processed: {0} + Downloaded: {0} of {1} The ConvertTo-Json and ConvertFrom-Json cmdlets require the 'Json.Net' module. {0} From 49ca9f4ea60fefe9046972041276141ef55700d5 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Fri, 15 Jan 2021 22:01:06 +0000 Subject: [PATCH 08/18] cap percentage at 100 as special test cases using -Resume parameter made it exceed 100% --- .../commands/utility/WebCmdlet/StreamHelper.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs index b1b1d55a443..9de206cce8d 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs @@ -7,6 +7,7 @@ using System.Management.Automation; using System.Management.Automation.Internal; using System.Net.Http; +using System.Net.Http.Headers; using System.Text; using System.Text.RegularExpressions; using System.Threading; @@ -236,7 +237,7 @@ private void Initialize() DisplayHumanReadableFileSize(_contentLength is null ? 0 : (long)_contentLength)); if (_contentLength != null && _contentLength > 0) { - record.PercentComplete = (int)(totalLength * 100 / (long)_contentLength); + record.PercentComplete = Math.Min((int)(totalLength * 100 / (long)_contentLength), 100); } _ownerCmdlet.WriteProgress(record); @@ -332,7 +333,7 @@ internal static void WriteToStream(Stream input, Stream output, PSCmdlet cmdlet, if (contentLength != null && contentLength > 0) { - record.PercentComplete = (int)(output.Position * 100 / (long)contentLength); + record.PercentComplete = Math.Min((int)(output.Position * 100 / (long)contentLength), 100); } cmdlet.WriteProgress(record); From df87e7dc32a65699bfede14463835c418ba6af2f Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Sun, 17 Jan 2021 18:45:12 +0000 Subject: [PATCH 09/18] Calculate total download size only once --- .../commands/utility/WebCmdlet/StreamHelper.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs index 9de206cce8d..2a7b92d04d4 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs @@ -227,6 +227,7 @@ private void Initialize() long totalLength = 0; byte[] buffer = new byte[StreamHelper.ChunkSize]; ProgressRecord record = new(StreamHelper.ActivityId, WebCmdletStrings.ReadResponseProgressActivity, "statusDescriptionPlaceholder"); + string totalDownloadSize = DisplayHumanReadableFileSize(_contentLength is null ? 0 : (long)_contentLength); for (int read = 1; read > 0; totalLength += read) { if (_ownerCmdlet != null) @@ -234,7 +235,7 @@ private void Initialize() record.StatusDescription = StringUtil.Format( WebCmdletStrings.ReadResponseProgressStatus, DisplayHumanReadableFileSize(totalLength), - DisplayHumanReadableFileSize(_contentLength is null ? 0 : (long)_contentLength)); + totalDownloadSize); if (_contentLength != null && _contentLength > 0) { record.PercentComplete = Math.Min((int)(totalLength * 100 / (long)_contentLength), 100); @@ -322,6 +323,7 @@ internal static void WriteToStream(Stream input, Stream output, PSCmdlet cmdlet, ActivityId, WebCmdletStrings.WriteRequestProgressActivity, WebCmdletStrings.WriteRequestProgressStatus); + string totalDownloadSize = WebResponseContentMemoryStream.DisplayHumanReadableFileSize(contentLength is null ? 0 : (long)contentLength); try { do @@ -329,7 +331,7 @@ internal static void WriteToStream(Stream input, Stream output, PSCmdlet cmdlet, record.StatusDescription = StringUtil.Format( WebCmdletStrings.WriteRequestProgressStatus, WebResponseContentMemoryStream.DisplayHumanReadableFileSize(output.Position), - WebResponseContentMemoryStream.DisplayHumanReadableFileSize(contentLength is null ? 0 : (long)contentLength)); + totalDownloadSize); if (contentLength != null && contentLength > 0) { From 1503a9e320076379f8ac6c4386f6b4eb4ae6b583 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Thu, 21 Jan 2021 23:02:05 +0000 Subject: [PATCH 10/18] Move DisplayHumanReadableFileSize into Utils.cs and cleanup using there. Replace "0 Bytes" with "???" when download size is not known --- .../utility/WebCmdlet/StreamHelper.cs | 30 +++---------------- .../engine/Utils.cs | 22 ++++++++++++-- test/xUnit/csharp/test_Utils.cs | 2 +- 3 files changed, 24 insertions(+), 30 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs index 2a7b92d04d4..8167431115d 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs @@ -7,14 +7,11 @@ using System.Management.Automation; using System.Management.Automation.Internal; using System.Net.Http; -using System.Net.Http.Headers; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("powershell-tests,PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] - namespace Microsoft.PowerShell.Commands { /// @@ -227,14 +224,14 @@ private void Initialize() long totalLength = 0; byte[] buffer = new byte[StreamHelper.ChunkSize]; ProgressRecord record = new(StreamHelper.ActivityId, WebCmdletStrings.ReadResponseProgressActivity, "statusDescriptionPlaceholder"); - string totalDownloadSize = DisplayHumanReadableFileSize(_contentLength is null ? 0 : (long)_contentLength); + string totalDownloadSize = _contentLength is null ? "???" : Utils.DisplayHumanReadableFileSize((long)_contentLength); for (int read = 1; read > 0; totalLength += read) { if (_ownerCmdlet != null) { record.StatusDescription = StringUtil.Format( WebCmdletStrings.ReadResponseProgressStatus, - DisplayHumanReadableFileSize(totalLength), + Utils.DisplayHumanReadableFileSize(totalLength), totalDownloadSize); if (_contentLength != null && _contentLength > 0) { @@ -274,25 +271,6 @@ private void Initialize() throw; } } - - private enum FileSizeUnit - { - Byte, KB, MB, GB, TB, PB, EB - } - - internal static string DisplayHumanReadableFileSize(long bytes) - { - if (bytes <= 0) - { - return $"0 {FileSizeUnit.Byte}"; - } - - var fileSizeUnit = (FileSizeUnit)(Math.Log10(bytes) / 3); - double value = bytes / (double)Math.Pow(1024, (long)fileSizeUnit); - var significantDigits = (int)fileSizeUnit; - var format = "0." + new string('0', significantDigits); - return value.ToString(format) + $" {fileSizeUnit}"; - } } internal static class StreamHelper @@ -323,14 +301,14 @@ internal static void WriteToStream(Stream input, Stream output, PSCmdlet cmdlet, ActivityId, WebCmdletStrings.WriteRequestProgressActivity, WebCmdletStrings.WriteRequestProgressStatus); - string totalDownloadSize = WebResponseContentMemoryStream.DisplayHumanReadableFileSize(contentLength is null ? 0 : (long)contentLength); + string totalDownloadSize = contentLength is null ? "???" : Utils.DisplayHumanReadableFileSize((long)contentLength); try { do { record.StatusDescription = StringUtil.Format( WebCmdletStrings.WriteRequestProgressStatus, - WebResponseContentMemoryStream.DisplayHumanReadableFileSize(output.Position), + Utils.DisplayHumanReadableFileSize(output.Position), totalDownloadSize); if (contentLength != null && contentLength > 0) diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index 6a4a863d23c..2943cab9962 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -5,8 +5,6 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.ComponentModel; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; @@ -19,7 +17,6 @@ using System.Management.Automation.Security; using System.Numerics; using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security; #if !UNIX @@ -1889,6 +1886,25 @@ internal static string GetFormatStyleString(FormatStyle formatStyle) } #endregion + + private enum FileSizeUnit + { + Byte, KB, MB, GB, TB, PB, EB + } + + internal static string DisplayHumanReadableFileSize(long bytes) + { + if (bytes <= 0) + { + return $"0 {FileSizeUnit.Byte}"; + } + + var fileSizeUnit = (FileSizeUnit)(Math.Log10(bytes) / 3); + double value = bytes / (double)Math.Pow(1024, (long)fileSizeUnit); + var significantDigits = (int)fileSizeUnit; + var format = "0." + new string('0', significantDigits); + return value.ToString(format) + $" {fileSizeUnit}"; + } } #region ImplicitRemotingBatching diff --git a/test/xUnit/csharp/test_Utils.cs b/test/xUnit/csharp/test_Utils.cs index 19be09c31fa..dac50ae089d 100644 --- a/test/xUnit/csharp/test_Utils.cs +++ b/test/xUnit/csharp/test_Utils.cs @@ -34,7 +34,7 @@ public static void TestIsWinPEHost() [InlineData(long.MaxValue, "8.000000 EB")] public static void DisplayHumanReadableFileSize(long bytes, string expected) { - Assert.Equal(expected, WebResponseContentMemoryStream.DisplayHumanReadableFileSize(bytes)); + Assert.Equal(expected, Utils.DisplayHumanReadableFileSize(bytes)); } [Fact] From 0b125c730cf9b17bc4a255183ef263971236dc35 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Sat, 24 Apr 2021 22:46:13 +0100 Subject: [PATCH 11/18] Use switch statement instead of doing maths to compute file size unit --- .../engine/Utils.cs | 28 ++++++++----------- test/xUnit/csharp/test_Utils.cs | 4 +-- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index 2943cab9962..3f034800486 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -1886,24 +1886,20 @@ internal static string GetFormatStyleString(FormatStyle formatStyle) } #endregion - - private enum FileSizeUnit - { - Byte, KB, MB, GB, TB, PB, EB - } - + internal static string DisplayHumanReadableFileSize(long bytes) { - if (bytes <= 0) - { - return $"0 {FileSizeUnit.Byte}"; - } - - var fileSizeUnit = (FileSizeUnit)(Math.Log10(bytes) / 3); - double value = bytes / (double)Math.Pow(1024, (long)fileSizeUnit); - var significantDigits = (int)fileSizeUnit; - var format = "0." + new string('0', significantDigits); - return value.ToString(format) + $" {fileSizeUnit}"; + return bytes switch + { + >= 1152921504606847000 => $"{(bytes / 1152921504606847000.0).ToString("0.000000000")} EB", + < 1152921504606847000 and >= 1125899906842624 => $"{(bytes / 1125899906842624.0).ToString("0.0000000")} PB", + < 1125899906842624 and >= 1099511627776 => $"{(bytes / 1099511627776.0).ToString("0.00000")} TB", + < 1125899906842624 and >= 1073741824 => $"{(bytes / 1073741824.0).ToString("0.000")} GB", + < 1073741824 and >= 1048576 => $"{(bytes / 1048576.0).ToString("0.0")} MB", + < 1048576 and >= 1024 => $"{(bytes / 1024.0).ToString("0.0")} KB", + < 1024 and >= 0 => $"{bytes} Byte", + _ => $"0 Byte" + }; } } diff --git a/test/xUnit/csharp/test_Utils.cs b/test/xUnit/csharp/test_Utils.cs index dac50ae089d..a36fa453059 100644 --- a/test/xUnit/csharp/test_Utils.cs +++ b/test/xUnit/csharp/test_Utils.cs @@ -29,9 +29,9 @@ public static void TestIsWinPEHost() [InlineData(1, "1 Byte")] [InlineData(1024, "1.0 KB")] [InlineData(3000, "2.9 KB")] - [InlineData(1024 * 1024, "1.00 MB")] + [InlineData(1024 * 1024, "1.0 MB")] [InlineData(1024 * 1024 * 1024, "1.000 GB")] - [InlineData(long.MaxValue, "8.000000 EB")] + [InlineData(long.MaxValue, "8.000000000 EB")] public static void DisplayHumanReadableFileSize(long bytes, string expected) { Assert.Equal(expected, Utils.DisplayHumanReadableFileSize(bytes)); From bfd8e27a35ba235285fdfd32ad1c8199b1cf7918 Mon Sep 17 00:00:00 2001 From: "Christoph Bergmeister [MVP]" Date: Wed, 25 Aug 2021 23:16:44 +0100 Subject: [PATCH 12/18] Apply suggestions from code review(Byte -> Bytes) Co-authored-by: Robert Holt --- src/System.Management.Automation/engine/Utils.cs | 4 ++-- test/xUnit/csharp/test_Utils.cs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index 0dd55cdca04..b8b4e9fd7db 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -1897,8 +1897,8 @@ internal static string DisplayHumanReadableFileSize(long bytes) < 1125899906842624 and >= 1073741824 => $"{(bytes / 1073741824.0).ToString("0.000")} GB", < 1073741824 and >= 1048576 => $"{(bytes / 1048576.0).ToString("0.0")} MB", < 1048576 and >= 1024 => $"{(bytes / 1024.0).ToString("0.0")} KB", - < 1024 and >= 0 => $"{bytes} Byte", - _ => $"0 Byte" + < 1024 and >= 0 => $"{bytes} Bytes", + _ => $"0 Bytes" }; } } diff --git a/test/xUnit/csharp/test_Utils.cs b/test/xUnit/csharp/test_Utils.cs index a36fa453059..2cafe9e3f12 100644 --- a/test/xUnit/csharp/test_Utils.cs +++ b/test/xUnit/csharp/test_Utils.cs @@ -23,10 +23,10 @@ public static void TestIsWinPEHost() } [Theory] - [InlineData(long.MinValue, "0 Byte")] - [InlineData(-1, "0 Byte")] - [InlineData(0, "0 Byte")] - [InlineData(1, "1 Byte")] + [InlineData(long.MinValue, "0 Bytes")] + [InlineData(-1, "0 Bytes")] + [InlineData(0, "0 Bytes")] + [InlineData(1, "1 Bytes")] [InlineData(1024, "1.0 KB")] [InlineData(3000, "2.9 KB")] [InlineData(1024 * 1024, "1.0 MB")] From e4eb7ac5a8cb6075d80d408295a6a10dc34eff5e Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Wed, 25 Aug 2021 23:52:19 +0100 Subject: [PATCH 13/18] Fix upper range for GB and add more test cases --- src/System.Management.Automation/engine/Utils.cs | 2 +- test/xUnit/csharp/test_Utils.cs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index b8b4e9fd7db..33f8348ae1d 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -1894,7 +1894,7 @@ internal static string DisplayHumanReadableFileSize(long bytes) >= 1152921504606847000 => $"{(bytes / 1152921504606847000.0).ToString("0.000000000")} EB", < 1152921504606847000 and >= 1125899906842624 => $"{(bytes / 1125899906842624.0).ToString("0.0000000")} PB", < 1125899906842624 and >= 1099511627776 => $"{(bytes / 1099511627776.0).ToString("0.00000")} TB", - < 1125899906842624 and >= 1073741824 => $"{(bytes / 1073741824.0).ToString("0.000")} GB", + < 1099511627776 and >= 1073741824 => $"{(bytes / 1073741824.0).ToString("0.000")} GB", < 1073741824 and >= 1048576 => $"{(bytes / 1048576.0).ToString("0.0")} MB", < 1048576 and >= 1024 => $"{(bytes / 1024.0).ToString("0.0")} KB", < 1024 and >= 0 => $"{bytes} Bytes", diff --git a/test/xUnit/csharp/test_Utils.cs b/test/xUnit/csharp/test_Utils.cs index 2cafe9e3f12..964b13468b6 100644 --- a/test/xUnit/csharp/test_Utils.cs +++ b/test/xUnit/csharp/test_Utils.cs @@ -31,6 +31,8 @@ public static void TestIsWinPEHost() [InlineData(3000, "2.9 KB")] [InlineData(1024 * 1024, "1.0 MB")] [InlineData(1024 * 1024 * 1024, "1.000 GB")] + [InlineData((long)(1024 * 1024 * 1024) * 1024, "1.0000 TB")] + [InlineData((long)(1024 * 1024 * 1024) * 1024 * 1024, "1.00000 PB")] [InlineData(long.MaxValue, "8.000000000 EB")] public static void DisplayHumanReadableFileSize(long bytes, string expected) { From b4c242b222424ccc36e32e75b0e597f94bfead36 Mon Sep 17 00:00:00 2001 From: "Christoph Bergmeister [MVP]" Date: Thu, 26 Aug 2021 00:25:36 +0100 Subject: [PATCH 14/18] Fix expected test result of new test cases --- test/xUnit/csharp/test_Utils.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/xUnit/csharp/test_Utils.cs b/test/xUnit/csharp/test_Utils.cs index 964b13468b6..bf562f3a8a4 100644 --- a/test/xUnit/csharp/test_Utils.cs +++ b/test/xUnit/csharp/test_Utils.cs @@ -31,8 +31,8 @@ public static void TestIsWinPEHost() [InlineData(3000, "2.9 KB")] [InlineData(1024 * 1024, "1.0 MB")] [InlineData(1024 * 1024 * 1024, "1.000 GB")] - [InlineData((long)(1024 * 1024 * 1024) * 1024, "1.0000 TB")] - [InlineData((long)(1024 * 1024 * 1024) * 1024 * 1024, "1.00000 PB")] + [InlineData((long)(1024 * 1024 * 1024) * 1024, "1.00000 TB")] + [InlineData((long)(1024 * 1024 * 1024) * 1024 * 1024, "1.0000000 PB")] [InlineData(long.MaxValue, "8.000000000 EB")] public static void DisplayHumanReadableFileSize(long bytes, string expected) { From e8532db8a1f880928e517c968a856784fbb0a7e4 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Tue, 13 Sep 2022 10:08:16 +0100 Subject: [PATCH 15/18] Rename totalLength to totalRead to address Keith's comment: https://github.com/PowerShell/PowerShell/pull/14611#pullrequestreview-739826847 --- .../commands/utility/WebCmdlet/StreamHelper.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs index 148cb8cdd24..7e604361a25 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs @@ -221,21 +221,21 @@ private void Initialize() _isInitialized = true; try { - long totalLength = 0; + long totalRead = 0; byte[] buffer = new byte[StreamHelper.ChunkSize]; ProgressRecord record = new(StreamHelper.ActivityId, WebCmdletStrings.ReadResponseProgressActivity, "statusDescriptionPlaceholder"); string totalDownloadSize = _contentLength is null ? "???" : Utils.DisplayHumanReadableFileSize((long)_contentLength); - for (int read = 1; read > 0; totalLength += read) + for (int read = 1; read > 0; totalRead += read) { if (_ownerCmdlet != null) { record.StatusDescription = StringUtil.Format( WebCmdletStrings.ReadResponseProgressStatus, - Utils.DisplayHumanReadableFileSize(totalLength), + Utils.DisplayHumanReadableFileSize(totalRead), totalDownloadSize); if (_contentLength != null && _contentLength > 0) { - record.PercentComplete = Math.Min((int)(totalLength * 100 / (long)_contentLength), 100); + record.PercentComplete = Math.Min((int)(totalRead * 100 / (long)_contentLength), 100); } _ownerCmdlet.WriteProgress(record); @@ -256,13 +256,13 @@ private void Initialize() if (_ownerCmdlet != null) { - record.StatusDescription = StringUtil.Format(WebCmdletStrings.ReadResponseComplete, totalLength); + record.StatusDescription = StringUtil.Format(WebCmdletStrings.ReadResponseComplete, totalRead); record.RecordType = ProgressRecordType.Completed; _ownerCmdlet.WriteProgress(record); } // make sure the length is set appropriately - base.SetLength(totalLength); + base.SetLength(totalRead); base.Seek(0, SeekOrigin.Begin); } catch (Exception) From cae26c259746281f0837b3175e53eed0bcf930a8 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Wed, 14 Sep 2022 09:00:55 +0100 Subject: [PATCH 16/18] Update src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs as per suggestion Co-authored-by: Dongbo Wang --- .../commands/utility/WebCmdlet/StreamHelper.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs index 7e604361a25..ad640dcfd41 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/StreamHelper.cs @@ -233,7 +233,8 @@ private void Initialize() WebCmdletStrings.ReadResponseProgressStatus, Utils.DisplayHumanReadableFileSize(totalRead), totalDownloadSize); - if (_contentLength != null && _contentLength > 0) + + if (_contentLength > 0) { record.PercentComplete = Math.Min((int)(totalRead * 100 / (long)_contentLength), 100); } From 25185e5d88fb030d238b097b1abb06491d561ee0 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Wed, 14 Sep 2022 09:09:42 +0100 Subject: [PATCH 17/18] Reverse order in switch statement of DisplayHumanReadableFileSize --- src/System.Management.Automation/engine/Utils.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index 30d09a2735a..e4816496492 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -1549,14 +1549,14 @@ internal static string DisplayHumanReadableFileSize(long bytes) { return bytes switch { - >= 1152921504606847000 => $"{(bytes / 1152921504606847000.0).ToString("0.000000000")} EB", - < 1152921504606847000 and >= 1125899906842624 => $"{(bytes / 1125899906842624.0).ToString("0.0000000")} PB", - < 1125899906842624 and >= 1099511627776 => $"{(bytes / 1099511627776.0).ToString("0.00000")} TB", - < 1099511627776 and >= 1073741824 => $"{(bytes / 1073741824.0).ToString("0.000")} GB", - < 1073741824 and >= 1048576 => $"{(bytes / 1048576.0).ToString("0.0")} MB", - < 1048576 and >= 1024 => $"{(bytes / 1024.0).ToString("0.0")} KB", + _ => $"0 Bytes", < 1024 and >= 0 => $"{bytes} Bytes", - _ => $"0 Bytes" + < 1048576 and >= 1024 => $"{(bytes / 1024.0).ToString("0.0")} KB", + < 1073741824 and >= 1048576 => $"{(bytes / 1048576.0).ToString("0.0")} MB", + < 1099511627776 and >= 1073741824 => $"{(bytes / 1073741824.0).ToString("0.000")} GB", + < 1125899906842624 and >= 1099511627776 => $"{(bytes / 1099511627776.0).ToString("0.00000")} TB", + < 1152921504606847000 and >= 1125899906842624 => $"{(bytes / 1125899906842624.0).ToString("0.0000000")} PB", + >= 1152921504606847000 => $"{(bytes / 1152921504606847000.0).ToString("0.000000000")} EB", }; } } From 5c95fca5541b015ab6cce044a7f92b810ee4e7c7 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Wed, 14 Sep 2022 09:20:38 +0100 Subject: [PATCH 18/18] Fix syntax error in last commit as switch statement requires default path to come last --- src/System.Management.Automation/engine/Utils.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index e4816496492..bc28b5a5d50 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -1549,7 +1549,6 @@ internal static string DisplayHumanReadableFileSize(long bytes) { return bytes switch { - _ => $"0 Bytes", < 1024 and >= 0 => $"{bytes} Bytes", < 1048576 and >= 1024 => $"{(bytes / 1024.0).ToString("0.0")} KB", < 1073741824 and >= 1048576 => $"{(bytes / 1048576.0).ToString("0.0")} MB", @@ -1557,6 +1556,7 @@ internal static string DisplayHumanReadableFileSize(long bytes) < 1125899906842624 and >= 1099511627776 => $"{(bytes / 1099511627776.0).ToString("0.00000")} TB", < 1152921504606847000 and >= 1125899906842624 => $"{(bytes / 1125899906842624.0).ToString("0.0000000")} PB", >= 1152921504606847000 => $"{(bytes / 1152921504606847000.0).ToString("0.000000000")} EB", + _ => $"0 Bytes", }; } }