From 95029314938007317ad8938bc8bf977975093e2d Mon Sep 17 00:00:00 2001 From: mkht Date: Tue, 9 May 2023 07:57:27 +0900 Subject: [PATCH] Fix HTTP status from 409 to 429 for WebCmdlets to get retry interval from Retry-After header. (#19622) --- .../Common/WebRequestPSCmdlet.Common.cs | 2 +- .../WebCmdlets.Tests.ps1 | 64 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) 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 60ee93159..7a53e22f6 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 @@ -1339,7 +1339,7 @@ namespace Microsoft.PowerShell.Commands // If the status code is 429 get the retry interval from the Headers. // Ignore broken header and its value. - if (response.StatusCode is HttpStatusCode.Conflict && response.Headers.TryGetValues(HttpKnownHeaderNames.RetryAfter, out IEnumerable retryAfter)) + if (response.StatusCode is HttpStatusCode.TooManyRequests && response.Headers.TryGetValues(HttpKnownHeaderNames.RetryAfter, out IEnumerable retryAfter)) { try { diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 2b2968ea3..117d42ac2 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -2157,6 +2157,38 @@ Describe "Invoke-WebRequest tests" -Tags "Feature", "RequireAdminOnWindows" { $jsonResult = $result.output.Content | ConvertFrom-Json $jsonResult.SessionId | Should -BeExactly $sessionId } + + It "Invoke-WebRequest respects the Retry-After header value in 429 status" { + + $Query = @{ + statusCode = 429 + reposnsephrase = 'Too Many Requests' + contenttype = 'application/json' + body = '{"message":"oops"}' + headers = '{"Retry-After":"1"}' + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $Query + $verboseFile = Join-Path $TestDrive -ChildPath verbose.txt + $result = Invoke-WebRequest -Uri $uri -MaximumRetryCount 1 -RetryIntervalSec 3 -SkipHttpErrorCheck -Verbose 4>$verbosefile + + $verboseFile | Should -FileContentMatch 'Retrying after interval of 1 seconds. Status code for previous attempt: TooManyRequests' + } + + It "Invoke-WebRequest ignores the Retry-After header value NOT in 429 status" { + + $Query = @{ + statusCode = 409 + reposnsephrase = 'Conflict' + contenttype = 'application/json' + body = '{"message":"oops"}' + headers = '{"Retry-After":"1"}' + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $Query + $verboseFile = Join-Path $TestDrive -ChildPath verbose.txt + $result = Invoke-WebRequest -Uri $uri -MaximumRetryCount 1 -RetryIntervalSec 3 -SkipHttpErrorCheck -Verbose 4>$verbosefile + + $verboseFile | Should -FileContentMatch 'Retrying after interval of 3 seconds. Status code for previous attempt: Conflict' + } } Context "Regex Parsing" { @@ -4047,6 +4079,38 @@ Describe "Invoke-RestMethod tests" -Tags "Feature", "RequireAdminOnWindows" { $result.output.failureResponsesSent | Should -Be 1 $result.output.sessionId | Should -BeExactly $sessionId } + + It "Invoke-RestMethod respects the Retry-After header value in 429 status" { + + $Query = @{ + statusCode = 429 + reposnsephrase = 'Too Many Requests' + contenttype = 'application/json' + body = '{"message":"oops"}' + headers = '{"Retry-After":"1"}' + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $Query + $verboseFile = Join-Path $TestDrive -ChildPath verbose.txt + $result = Invoke-RestMethod -Uri $uri -MaximumRetryCount 1 -RetryIntervalSec 3 -SkipHttpErrorCheck -Verbose 4>$verbosefile + + $verboseFile | Should -FileContentMatch 'Retrying after interval of 1 seconds. Status code for previous attempt: TooManyRequests' + } + + It "Invoke-RestMethod ignores the Retry-After header value NOT in 429 status" { + + $Query = @{ + statusCode = 409 + reposnsephrase = 'Conflict' + contenttype = 'application/json' + body = '{"message":"oops"}' + headers = '{"Retry-After":"1"}' + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $Query + $verboseFile = Join-Path $TestDrive -ChildPath verbose.txt + $result = Invoke-RestMethod -Uri $uri -MaximumRetryCount 1 -RetryIntervalSec 3 -SkipHttpErrorCheck -Verbose 4>$verbosefile + + $verboseFile | Should -FileContentMatch 'Retrying after interval of 3 seconds. Status code for previous attempt: Conflict' + } } }