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 1012cad2e84..ca78ff370b2 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 @@ -80,7 +80,7 @@ internal override void ProcessResponse(HttpResponseMessage response) ArgumentNullException.ThrowIfNull(response); ArgumentNullException.ThrowIfNull(_cancelToken); - TimeSpan perReadTimeout = NetworkTimeout; + TimeSpan perReadTimeout = ConvertTimeoutSecondsToTimeSpan(OperationTimeoutSeconds); Stream baseResponseStream = StreamHelper.GetResponseStream(response, _cancelToken.Token); if (ShouldWriteToPipeline) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs index 7dc724c217e..f0077d0040f 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs @@ -266,7 +266,7 @@ public abstract class WebRequestPSCmdlet : PSCmdlet, IDisposable public virtual SwitchParameter DisableKeepAlive { get; set; } /// - /// Gets or sets the ConnectTimeOutSec property. + /// Gets or sets the ConnectionTimeoutSeconds property. /// /// /// This property applies to sending the request and receiving the response headers only. @@ -274,17 +274,17 @@ public abstract class WebRequestPSCmdlet : PSCmdlet, IDisposable [Alias("TimeoutSec")] [Parameter] [ValidateRange(0, int.MaxValue)] - public virtual int ConnectTimeoutSec { get; set; } + public virtual int ConnectionTimeoutSeconds { get; set; } /// - /// Gets or sets the NetworkTimeoutSec property. + /// Gets or sets the OperationTimeoutSeconds property. /// /// - /// This property applies to receiving the response body. + /// This property applies to each read operation when receiving the response body. /// [Parameter] [ValidateRange(0, int.MaxValue)] - public virtual int NetworkTimeoutSec { get; set; } + public virtual int OperationTimeoutSeconds { get; set; } /// /// Gets or sets the Headers property. @@ -511,8 +511,6 @@ public virtual string CustomMethod internal bool ShouldWriteToPipeline => !ShouldSaveToOutFile || PassThru; - internal TimeSpan NetworkTimeout => NetworkTimeoutSec > 0 ? TimeSpan.FromSeconds(NetworkTimeoutSec) : Timeout.InfiniteTimeSpan; - #endregion Helper Properties #region Abstract Methods @@ -586,7 +584,7 @@ protected override void ProcessRecord() string respVerboseMsg = contentLength is null ? string.Format(CultureInfo.CurrentCulture, WebCmdletStrings.WebResponseNoSizeVerboseMsg, response.Version, contentType) : string.Format(CultureInfo.CurrentCulture, WebCmdletStrings.WebResponseVerboseMsg, response.Version, contentLength, contentType); - + WriteVerbose(respVerboseMsg); bool _isSuccess = response.IsSuccessStatusCode; @@ -638,7 +636,7 @@ protected override void ProcessRecord() try { // We can't use ReadAsStringAsync because it doesn't have per read timeouts - TimeSpan perReadTimeout = NetworkTimeout; + TimeSpan perReadTimeout = ConvertTimeoutSecondsToTimeSpan(OperationTimeoutSeconds); string characterSet = WebResponseHelper.GetCharacterSet(response); var responseStream = StreamHelper.GetResponseStream(response, _cancelToken.Token); int initialCapacity = (int)Math.Min(contentLength ?? StreamHelper.DefaultReadBuffer, StreamHelper.DefaultReadBuffer); @@ -1043,7 +1041,7 @@ internal virtual void PrepareSession() WebSession.RetryIntervalInSeconds = RetryIntervalSec; } - WebSession.ConnectTimeoutSec = ConnectTimeoutSec; + WebSession.ConnectionTimeout = ConvertTimeoutSecondsToTimeSpan(ConnectionTimeoutSeconds); } internal virtual HttpClient GetHttpClient(bool handleRedirect) @@ -1411,6 +1409,9 @@ internal virtual void UpdateSession(HttpResponseMessage response) #endregion Virtual Methods #region Helper Methods + + internal static TimeSpan ConvertTimeoutSecondsToTimeSpan(int timeout) => timeout > 0 ? TimeSpan.FromSeconds(timeout) : Timeout.InfiniteTimeSpan; + private Uri PrepareUri(Uri uri) { uri = CheckProtocol(uri); 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 85c0012b596..026bbe866e5 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 @@ -36,7 +36,7 @@ public InvokeWebRequestCommand() : base() internal override void ProcessResponse(HttpResponseMessage response) { ArgumentNullException.ThrowIfNull(response); - TimeSpan perReadTimeout = NetworkTimeout; + TimeSpan perReadTimeout = ConvertTimeoutSecondsToTimeSpan(OperationTimeoutSeconds); Stream responseStream = StreamHelper.GetResponseStream(response, _cancelToken.Token); if (ShouldWriteToPipeline) { diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebRequestSession.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebRequestSession.cs index 03e76ea8b26..a55a7dde387 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebRequestSession.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/WebRequestSession.cs @@ -32,7 +32,7 @@ public class WebRequestSession : IDisposable private bool _skipCertificateCheck; private bool _noProxy; private bool _disposed; - private int _connectTimeoutSec; + private TimeSpan _connectionTimeout; /// /// Contains true if an existing HttpClient had to be disposed and recreated since the WebSession was last used. @@ -142,7 +142,7 @@ public WebRequestSession() internal bool SkipCertificateCheck { set => SetStructVar(ref _skipCertificateCheck, value); } - internal int ConnectTimeoutSec { set => SetStructVar(ref _connectTimeoutSec, value); } + internal TimeSpan ConnectionTimeout { set => SetStructVar(ref _connectionTimeout, value); } internal bool NoProxy { @@ -240,7 +240,7 @@ private HttpClient CreateHttpClient() // Check timeout setting (in seconds instead of milliseconds as in HttpWebRequest) return new HttpClient(handler) { - Timeout = _connectTimeoutSec > 0 ? TimeSpan.FromSeconds(_connectTimeoutSec) : Timeout.InfiniteTimeSpan + Timeout = _connectionTimeout }; } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 98e51eb3c32..2220574743b 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -241,10 +241,10 @@ function ExecuteRequestWithCustomUserAgent { try { $Params = @{ - Uri = $Uri - ConnectTimeoutSec = 5 - UserAgent = $UserAgent - SkipHeaderValidation = $SkipHeaderValidation.IsPresent + Uri = $Uri + ConnectionTimeoutSeconds = 5 + UserAgent = $UserAgent + SkipHeaderValidation = $SkipHeaderValidation.IsPresent } if ($Cmdlet -eq 'Invoke-WebRequest') { $result.Output = Invoke-WebRequest @Params @@ -608,9 +608,9 @@ Describe "Invoke-WebRequest tests" -Tags "Feature", "RequireAdminOnWindows" { $Result.Output.Content | Should -Match '测试123' } - It "Invoke-WebRequest validate ConnectTimeoutSec option" { + It "Invoke-WebRequest validate ConnectionTimeoutSeconds option" { $uri = Get-WebListenerUrl -Test 'Delay' -TestValue '5' - $command = "Invoke-WebRequest -Uri '$uri' -ConnectTimeoutSec 2" + $command = "Invoke-WebRequest -Uri '$uri' -ConnectionTimeoutSeconds 2" $result = ExecuteWebCommand -command $command $result.Error.FullyQualifiedErrorId | Should -Be "System.Threading.Tasks.TaskCanceledException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand" @@ -2636,9 +2636,9 @@ Describe "Invoke-RestMethod tests" -Tags "Feature", "RequireAdminOnWindows" { $Result.Output | Should -Match '测试123' } - It "Invoke-RestMethod validate ConnectTimeoutSec option" { + It "Invoke-RestMethod validate ConnectionTimeoutSeconds option" { $uri = Get-WebListenerUrl -Test 'Delay' -TestValue '5' - $command = "Invoke-RestMethod -Uri '$uri' -ConnectTimeoutSec 2" + $command = "Invoke-RestMethod -Uri '$uri' -ConnectionTimeoutSeconds 2" $result = ExecuteWebCommand -command $command $result.Error.FullyQualifiedErrorId | Should -Be "System.Threading.Tasks.TaskCanceledException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand" @@ -4422,7 +4422,7 @@ Describe 'Invoke-WebRequest and Invoke-RestMethod support Cancellation through C } } -Describe 'Invoke-WebRequest and Invoke-RestMethod support NetworkTimeoutSec' -Tags "CI", "RequireAdminOnWindows" { +Describe 'Invoke-WebRequest and Invoke-RestMethod support OperationTimeoutSeconds' -Tags "CI", "RequireAdminOnWindows" { BeforeAll { $oldProgress = $ProgressPreference $ProgressPreference = 'SilentlyContinue' @@ -4439,13 +4439,13 @@ Describe 'Invoke-WebRequest and Invoke-RestMethod support NetworkTimeoutSec' -Ta [string]$Command = 'Invoke-WebRequest', [string]$Arguments = '', [uri]$Uri, - [int]$NetworkTimeoutSec, + [int]$OperationTimeoutSeconds, [switch]$WillTimeout ) $invoke = "$Command -Uri `"$Uri`" $Arguments" - if ($PSBoundParameters.ContainsKey('NetworkTimeoutSec')) { - $invoke = "$invoke -NetworkTimeoutSec $NetworkTimeoutSec" + if ($PSBoundParameters.ContainsKey('OperationTimeoutSeconds')) { + $invoke = "$invoke -OperationTimeoutSeconds $OperationTimeoutSeconds" } $result = ExecuteWebCommand -command $invoke @@ -4458,43 +4458,43 @@ Describe 'Invoke-WebRequest and Invoke-RestMethod support NetworkTimeoutSec' -Ta } } - It 'Invoke-WebRequest: NetworkTimeoutSec does not cancel if stalls shorter than timeout but download takes longer than timeout' { + It 'Invoke-WebRequest: OperationTimeoutSeconds does not cancel if stalls shorter than timeout but download takes longer than timeout' { $uri = Get-WebListenerUrl -Test Stall -TestValue '2' -Query @{ chunks = 5 } - RunWithNetworkTimeout -Uri $uri -NetworkTimeoutSec 4 + RunWithNetworkTimeout -Uri $uri -OperationTimeoutSeconds 4 } - It 'Invoke-WebRequest: NetworkTimeoutSec cancels if stall lasts longer than NetworkTimeoutSec value' { + It 'Invoke-WebRequest: OperationTimeoutSeconds cancels if stall lasts longer than OperationTimeoutSeconds value' { $uri = Get-WebListenerUrl -Test Stall -TestValue 30 - RunWithNetworkTimeout -Uri $uri -NetworkTimeoutSec 3 -WillTimeout + RunWithNetworkTimeout -Uri $uri -OperationTimeoutSeconds 3 -WillTimeout } - It 'Invoke-WebRequest: NetworkTimeoutSec cancels if stall lasts longer than NetworkTimeoutSec value for HTTPS/gzip compression' { + It 'Invoke-WebRequest: OperationTimeoutSeconds cancels if stall lasts longer than OperationTimeoutSeconds value for HTTPS/gzip compression' { $uri = Get-WebListenerUrl -Https -Test StallGzip -TestValue 30 - RunWithNetworkTimeout -Uri $uri -NetworkTimeoutSec 3 -WillTimeout -Arguments '-SkipCertificateCheck' + RunWithNetworkTimeout -Uri $uri -OperationTimeoutSeconds 3 -WillTimeout -Arguments '-SkipCertificateCheck' } - It 'Invoke-RestMethod: NetworkTimeoutSec does not cancel if stalls shorter than timeout but download takes longer than timeout' { + It 'Invoke-RestMethod: OperationTimeoutSeconds does not cancel if stalls shorter than timeout but download takes longer than timeout' { $uri = Get-WebListenerUrl -Test Stall -TestValue '2' -Query @{ chunks = 5 } - RunWithNetworkTimeout -Command Invoke-RestMethod -Uri $uri -NetworkTimeoutSec 4 + RunWithNetworkTimeout -Command Invoke-RestMethod -Uri $uri -OperationTimeoutSeconds 4 } - It 'Invoke-RestMethod: NetworkTimeoutSec cancels if stall lasts longer than NetworkTimeoutSec value' { + It 'Invoke-RestMethod: OperationTimeoutSeconds cancels if stall lasts longer than OperationTimeoutSeconds value' { $uri = Get-WebListenerUrl -Test Stall -TestValue 30 - RunWithNetworkTimeout -Command Invoke-RestMethod -Uri $uri -NetworkTimeoutSec 2 -WillTimeout + RunWithNetworkTimeout -Command Invoke-RestMethod -Uri $uri -OperationTimeoutSeconds 2 -WillTimeout } - It 'Invoke-RestMethod: NetworkTimeoutSec cancels when doing XML atom processing' { + It 'Invoke-RestMethod: OperationTimeoutSeconds cancels when doing XML atom processing' { $uri = Get-WebListenerUrl -Test Stall -TestValue '30/application%2fxml' - RunWithNetworkTimeout -Command Invoke-RestMethod -Uri $uri -NetworkTimeoutSec 2 -WillTimeout + RunWithNetworkTimeout -Command Invoke-RestMethod -Uri $uri -OperationTimeoutSeconds 2 -WillTimeout } - It 'Invoke-RestMethod: NetworkTimeoutSec cancels when doing JSON processing' { + It 'Invoke-RestMethod: OperationTimeoutSeconds cancels when doing JSON processing' { $uri = Get-WebListenerUrl -Test Stall -TestValue '30/application%2fjson' - RunWithNetworkTimeout -Command Invoke-RestMethod -Uri $uri -NetworkTimeoutSec 2 -WillTimeout + RunWithNetworkTimeout -Command Invoke-RestMethod -Uri $uri -OperationTimeoutSeconds 2 -WillTimeout } - It 'Invoke-RestMethod: NetworkTimeoutSec cancels when doing XML atom processing for HTTPS/gzip compression' { + It 'Invoke-RestMethod: OperationTimeoutSeconds cancels when doing XML atom processing for HTTPS/gzip compression' { $uri = Get-WebListenerUrl -Https -Test StallGzip -TestValue 30/application%2fXML - RunWithNetworkTimeout -Command Invoke-RestMethod -Uri $uri -NetworkTimeoutSec 2 -WillTimeout -Arguments '-SkipCertificateCheck' + RunWithNetworkTimeout -Command Invoke-RestMethod -Uri $uri -OperationTimeoutSeconds 2 -WillTimeout -Arguments '-SkipCertificateCheck' } }