From b4467aa9da02df9aa0aaa59c9cc0ac9f77043419 Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Fri, 6 Jan 2023 00:31:50 +0100
Subject: [PATCH 01/27] Add PersistHTTPMethod parameter
---
.../utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs | 7 +++++++
1 file changed, 7 insertions(+)
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 e82bd7e5772..fde87624685 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
@@ -273,6 +273,13 @@ public abstract partial class WebRequestPSCmdlet : PSCmdlet
[ValidateNotNullOrEmpty]
public virtual string CustomMethod { get; set; }
+ ///
+ /// Gets or sets the PersistHTTPMethod property.
+ ///
+ [Parameter]
+ [ValidateSet("All", "300", "301", "302", "303", IgnoreCase = true)]
+ public virtual string[] PersistHTTPMethod { get; set; }
+
#endregion
#region NoProxy
From 720ece84c6afd42f8f4fb592785a2882f7ff861a Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Fri, 6 Jan 2023 00:33:05 +0100
Subject: [PATCH 02/27] PersistHTTPMethod handle redirect
---
.../utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs | 2 +-
1 file changed, 1 insertion(+), 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 fde87624685..138caa67e19 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
@@ -975,7 +975,7 @@ internal virtual HttpClient GetHttpClient(bool handleRedirect)
}
// This indicates GetResponse will handle redirects.
- if (handleRedirect)
+ if (handleRedirect || PersistHTTPMethod is not null)
{
handler.AllowAutoRedirect = false;
}
From 20520e68145e4055a16761ae8b3fa2dc0ba78a36 Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Fri, 6 Jan 2023 00:38:48 +0100
Subject: [PATCH 03/27] PersistHTTPMethod manual redirect
---
.../utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs | 4 +++-
1 file changed, 3 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 138caa67e19..d74ad09d61f 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
@@ -1319,8 +1319,10 @@ internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestM
_cancelToken = new CancellationTokenSource();
response = client.SendAsync(req, HttpCompletionOption.ResponseHeadersRead, _cancelToken.Token).GetAwaiter().GetResult();
+
+ bool sessionRedirect = WebSession.MaximumRedirection > 0 || WebSession.MaximumRedirection == -1;
- if (keepAuthorization && IsRedirectCode(response.StatusCode) && response.Headers.Location is not null)
+ if ((keepAuthorization || (PersistHTTPMethod is not null && sessionRedirect)) && IsRedirectCode(response.StatusCode) && response.Headers.Location is not null)
{
_cancelToken.Cancel();
_cancelToken = null;
From 1335810665e11bc1859401cdc6bfdd42d72da419 Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Fri, 6 Jan 2023 00:46:42 +0100
Subject: [PATCH 04/27] replace IsRedirectToGet with RequestRequiresForceGet
from dotnet
---
.../Common/WebRequestPSCmdlet.Common.cs | 37 +++++++++----------
1 file changed, 18 insertions(+), 19 deletions(-)
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 d74ad09d61f..b4a15f0e222 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
@@ -1274,20 +1274,20 @@ private static bool IsRedirectCode(HttpStatusCode code)
);
}
- // Returns true if the status code is a redirection code and the action requires switching from POST to GET on redirection.
- // NOTE: Some of these status codes map to the same underlying value but spelling them out for completeness.
- private static bool IsRedirectToGet(HttpStatusCode code)
+ // Returns true if the status code is a redirection code and the action requires switching to GET on redirection.
+ private static bool RequestRequiresForceGet(HttpStatusCode statusCode, WebRequestMethod requestMethod)
{
- return
- (
- code == HttpStatusCode.Found ||
- code == HttpStatusCode.Moved ||
- code == HttpStatusCode.Redirect ||
- code == HttpStatusCode.RedirectMethod ||
- code == HttpStatusCode.SeeOther ||
- code == HttpStatusCode.Ambiguous ||
- code == HttpStatusCode.MultipleChoices
- );
+ switch (statusCode)
+ {
+ case HttpStatusCode.Moved:
+ case HttpStatusCode.Found:
+ case HttpStatusCode.MultipleChoices:
+ return requestMethod == WebRequestMethod.Post;
+ case HttpStatusCode.SeeOther:
+ return requestMethod != WebRequestMethod.Get && requestMethod != WebRequestMethod.Head;
+ default:
+ return false;
+ }
}
// Returns true if the status code shows a server or client error and MaximumRetryCount > 0
@@ -1327,17 +1327,16 @@ internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestM
_cancelToken.Cancel();
_cancelToken = null;
- // if explicit count was provided, reduce it for this redirection.
+ // If explicit count was provided, reduce it for this redirection.
if (WebSession.MaximumRedirection > 0)
{
WebSession.MaximumRedirection--;
}
- // For selected redirects that used POST, GET must be used with the
- // redirected Location.
- // Since GET is the default; POST only occurs when -Method POST is used.
- if (Method == WebRequestMethod.Post && IsRedirectToGet(response.StatusCode))
+
+ // For selected redirects, GET must be used with the redirected Location.
+ // See https://msdn.microsoft.com/library/system.net.httpstatuscode(v=vs.110).aspx
+ if (RequestRequiresForceGet(response.StatusCode, Method))
{
- // See https://msdn.microsoft.com/library/system.net.httpstatuscode(v=vs.110).aspx
Method = WebRequestMethod.Get;
}
From a36718ca0660b56c08fba35b990b8189ab541599 Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Fri, 6 Jan 2023 00:54:13 +0100
Subject: [PATCH 05/27] Update IsRedirectCode with code from RedirectHandler.cs
---
.../Common/WebRequestPSCmdlet.Common.cs | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
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 b4a15f0e222..921c659267d 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
@@ -1265,13 +1265,18 @@ internal virtual void FillRequestStream(HttpRequestMessage request)
// Returns true if the status code is one of the supported redirection codes.
private static bool IsRedirectCode(HttpStatusCode code)
{
- int intCode = (int)code;
- return
- (
- (intCode >= 300 && intCode < 304) ||
- intCode == 307 ||
- intCode == 308
- );
+ switch (statusCode)
+ {
+ case HttpStatusCode.Moved:
+ case HttpStatusCode.Found:
+ case HttpStatusCode.SeeOther:
+ case HttpStatusCode.TemporaryRedirect:
+ case HttpStatusCode.MultipleChoices:
+ case HttpStatusCode.PermanentRedirect:
+ return true;
+ default:
+ return false;
+ }
}
// Returns true if the status code is a redirection code and the action requires switching to GET on redirection.
From 949954832ba0a7630b717489a3877de2abe40ae7 Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Fri, 6 Jan 2023 00:59:49 +0100
Subject: [PATCH 06/27] Add PersistHTTPMethod
---
.../Common/WebRequestPSCmdlet.Common.cs | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
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 921c659267d..dec8f857269 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
@@ -1341,6 +1341,23 @@ internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestM
// For selected redirects, GET must be used with the redirected Location.
// See https://msdn.microsoft.com/library/system.net.httpstatuscode(v=vs.110).aspx
if (RequestRequiresForceGet(response.StatusCode, Method))
+ {
+ if (PersistHTTPMethod is not null)
+ {
+ switch (response.StatusCode)
+ {
+ case HttpStatusCode.Moved when Array.Exists(PersistHTTPMethod, element => element == "301" || element == "All"):
+ case HttpStatusCode.Found when Array.Exists(PersistHTTPMethod, element => element == "302" || element == "All"):
+ case HttpStatusCode.SeeOther when Array.Exists(PersistHTTPMethod, element => element == "303" || element == "All"):
+ case HttpStatusCode.MultipleChoices when Array.Exists(PersistHTTPMethod, element => element == "300" || element == "All"):
+ break;
+ default:
+ Method = WebRequestMethod.Get;
+ break;
+ }
+ }
+ }
+ else
{
Method = WebRequestMethod.Get;
}
From 689455b44fea93ff69a7737d0ad184e334df43aa Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Fri, 6 Jan 2023 01:23:15 +0100
Subject: [PATCH 07/27] Fix error
---
.../utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs | 2 +-
1 file changed, 1 insertion(+), 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 dec8f857269..f17cea63f8b 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
@@ -1263,7 +1263,7 @@ internal virtual void FillRequestStream(HttpRequestMessage request)
}
// Returns true if the status code is one of the supported redirection codes.
- private static bool IsRedirectCode(HttpStatusCode code)
+ private static bool IsRedirectCode(HttpStatusCode statusCode)
{
switch (statusCode)
{
From 25ee798401c74c385f647d966135008ba94cd8bb Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Fri, 6 Jan 2023 01:48:26 +0100
Subject: [PATCH 08/27] fix test error (pasted else in the wrong place)
---
.../utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
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 f17cea63f8b..7c808d2788e 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
@@ -1356,10 +1356,10 @@ internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestM
break;
}
}
- }
- else
- {
- Method = WebRequestMethod.Get;
+ else
+ {
+ Method = WebRequestMethod.Get;
+ }
}
currentUri = new Uri(request.RequestUri, response.Headers.Location);
From 5278cf78441eb1d451e1c18c36c303d5163a9603 Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Fri, 6 Jan 2023 18:45:52 +0100
Subject: [PATCH 09/27] Convert to SwitchParameter and
PreserveHTTPMethodOnRedirect
---
.../Common/WebRequestPSCmdlet.Common.cs | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
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 7c808d2788e..b399d2bccd9 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
@@ -274,11 +274,10 @@ public abstract partial class WebRequestPSCmdlet : PSCmdlet
public virtual string CustomMethod { get; set; }
///
- /// Gets or sets the PersistHTTPMethod property.
+ /// Gets or sets the PreserveHTTPMethodOnRedirect property.
///
[Parameter]
- [ValidateSet("All", "300", "301", "302", "303", IgnoreCase = true)]
- public virtual string[] PersistHTTPMethod { get; set; }
+ public virtual SwitchParameter PreserveHTTPMethodOnRedirect { get; set; }
#endregion
@@ -975,7 +974,7 @@ internal virtual HttpClient GetHttpClient(bool handleRedirect)
}
// This indicates GetResponse will handle redirects.
- if (handleRedirect || PersistHTTPMethod is not null)
+ if (handleRedirect || PreserveHTTPMethodOnRedirect)
{
handler.AllowAutoRedirect = false;
}
@@ -1327,7 +1326,7 @@ internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestM
bool sessionRedirect = WebSession.MaximumRedirection > 0 || WebSession.MaximumRedirection == -1;
- if ((keepAuthorization || (PersistHTTPMethod is not null && sessionRedirect)) && IsRedirectCode(response.StatusCode) && response.Headers.Location is not null)
+ if ((keepAuthorization || (PreserveHTTPMethodOnRedirect && sessionRedirect)) && IsRedirectCode(response.StatusCode) && response.Headers.Location is not null)
{
_cancelToken.Cancel();
_cancelToken = null;
@@ -1342,14 +1341,14 @@ internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestM
// See https://msdn.microsoft.com/library/system.net.httpstatuscode(v=vs.110).aspx
if (RequestRequiresForceGet(response.StatusCode, Method))
{
- if (PersistHTTPMethod is not null)
+ if (PreserveHTTPMethodOnRedirect)
{
switch (response.StatusCode)
{
- case HttpStatusCode.Moved when Array.Exists(PersistHTTPMethod, element => element == "301" || element == "All"):
- case HttpStatusCode.Found when Array.Exists(PersistHTTPMethod, element => element == "302" || element == "All"):
- case HttpStatusCode.SeeOther when Array.Exists(PersistHTTPMethod, element => element == "303" || element == "All"):
- case HttpStatusCode.MultipleChoices when Array.Exists(PersistHTTPMethod, element => element == "300" || element == "All"):
+ case HttpStatusCode.Moved:
+ case HttpStatusCode.Found:
+ case HttpStatusCode.SeeOther:
+ case HttpStatusCode.MultipleChoices:
break;
default:
Method = WebRequestMethod.Get;
From 127d94c04e5d35d0c97dc1ea87a378aec386446c Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Fri, 6 Jan 2023 19:51:00 +0100
Subject: [PATCH 10/27] Follow suggestions
---
.../Common/WebRequestPSCmdlet.Common.cs | 18 ++----------------
1 file changed, 2 insertions(+), 16 deletions(-)
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 b399d2bccd9..06b59a51064 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
@@ -1279,6 +1279,7 @@ private static bool IsRedirectCode(HttpStatusCode statusCode)
}
// Returns true if the status code is a redirection code and the action requires switching to GET on redirection.
+ // See https://learn.microsoft.com/en-us/dotnet/api/system.net.httpstatuscode
private static bool RequestRequiresForceGet(HttpStatusCode statusCode, WebRequestMethod requestMethod)
{
switch (statusCode)
@@ -1338,24 +1339,9 @@ internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestM
}
// For selected redirects, GET must be used with the redirected Location.
- // See https://msdn.microsoft.com/library/system.net.httpstatuscode(v=vs.110).aspx
if (RequestRequiresForceGet(response.StatusCode, Method))
{
- if (PreserveHTTPMethodOnRedirect)
- {
- switch (response.StatusCode)
- {
- case HttpStatusCode.Moved:
- case HttpStatusCode.Found:
- case HttpStatusCode.SeeOther:
- case HttpStatusCode.MultipleChoices:
- break;
- default:
- Method = WebRequestMethod.Get;
- break;
- }
- }
- else
+ if (!PreserveHTTPMethodOnRedirect)
{
Method = WebRequestMethod.Get;
}
From 575e076556185da0b7209008568b5094b0e74076 Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Sat, 7 Jan 2023 10:55:11 +0100
Subject: [PATCH 11/27] join if
---
.../utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
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 06b59a51064..17496842350 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,12 +1339,9 @@ internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestM
}
// For selected redirects, GET must be used with the redirected Location.
- if (RequestRequiresForceGet(response.StatusCode, Method))
+ if (RequestRequiresForceGet(response.StatusCode, Method) && !PreserveHTTPMethodOnRedirect)
{
- if (!PreserveHTTPMethodOnRedirect)
- {
- Method = WebRequestMethod.Get;
- }
+ Method = WebRequestMethod.Get;
}
currentUri = new Uri(request.RequestUri, response.Headers.Location);
From b7e889a434852fb2d58fb304895c038e580eb137 Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Sat, 7 Jan 2023 11:07:55 +0100
Subject: [PATCH 12/27] Should Retry remove maximumretrycount add switch
---
.../Common/WebRequestPSCmdlet.Common.cs | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
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 17496842350..bc29e0fc88e 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
@@ -1296,14 +1296,16 @@ private static bool RequestRequiresForceGet(HttpStatusCode statusCode, WebReques
}
// Returns true if the status code shows a server or client error and MaximumRetryCount > 0
- private bool ShouldRetry(HttpStatusCode code)
+ private bool ShouldRetry(HttpStatusCode statusCode)
{
- int intCode = (int)code;
-
- return
- (
- (intCode == 304 || (intCode >= 400 && intCode <= 599)) && WebSession.MaximumRetryCount > 0
- );
+ switch ((int)statusCode)
+ {
+ case 304:
+ case >= 400 and <= 599:
+ return true;
+ default:
+ return false;
+ }
}
internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestMessage request, bool keepAuthorization)
From c9b5003586cbc168d367b4833cc1a03f1d93170b Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Sat, 7 Jan 2023 11:15:41 +0100
Subject: [PATCH 13/27] add static
---
.../utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs | 2 +-
1 file changed, 1 insertion(+), 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 bc29e0fc88e..313931d689d 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
@@ -1296,7 +1296,7 @@ private static bool RequestRequiresForceGet(HttpStatusCode statusCode, WebReques
}
// Returns true if the status code shows a server or client error and MaximumRetryCount > 0
- private bool ShouldRetry(HttpStatusCode statusCode)
+ private static bool ShouldRetry(HttpStatusCode statusCode)
{
switch ((int)statusCode)
{
From 065aa1fbeee67dd80989f76d09ef6d4eade5b038 Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Sun, 8 Jan 2023 17:45:33 +0100
Subject: [PATCH 14/27] RequestRequiresForceGet WebRequestMethod --> HttpMethod
---
.../utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
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 313931d689d..d28cb31fed0 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
@@ -1280,16 +1280,16 @@ private static bool IsRedirectCode(HttpStatusCode statusCode)
// Returns true if the status code is a redirection code and the action requires switching to GET on redirection.
// See https://learn.microsoft.com/en-us/dotnet/api/system.net.httpstatuscode
- private static bool RequestRequiresForceGet(HttpStatusCode statusCode, WebRequestMethod requestMethod)
+ private static bool RequestRequiresForceGet(HttpStatusCode statusCode, HttpMethod requestMethod)
{
switch (statusCode)
{
case HttpStatusCode.Moved:
case HttpStatusCode.Found:
case HttpStatusCode.MultipleChoices:
- return requestMethod == WebRequestMethod.Post;
+ return requestMethod == HttpMethod.Post;
case HttpStatusCode.SeeOther:
- return requestMethod != WebRequestMethod.Get && requestMethod != WebRequestMethod.Head;
+ return requestMethod != HttpMethod.Get && requestMethod != HttpMethod.Head;
default:
return false;
}
@@ -1341,7 +1341,7 @@ internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestM
}
// For selected redirects, GET must be used with the redirected Location.
- if (RequestRequiresForceGet(response.StatusCode, Method) && !PreserveHTTPMethodOnRedirect)
+ if (RequestRequiresForceGet(response.StatusCode, req.Method) && !PreserveHTTPMethodOnRedirect)
{
Method = WebRequestMethod.Get;
}
From a3438f6ed0785608dccd8faec3d7be3536b4d273 Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Mon, 9 Jan 2023 09:59:48 +0100
Subject: [PATCH 15/27] switch expressions
---
.../Common/WebRequestPSCmdlet.Common.cs | 57 +++++++------------
1 file changed, 20 insertions(+), 37 deletions(-)
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 d28cb31fed0..eadb3218c83 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
@@ -1262,51 +1262,34 @@ internal virtual void FillRequestStream(HttpRequestMessage request)
}
// Returns true if the status code is one of the supported redirection codes.
- private static bool IsRedirectCode(HttpStatusCode statusCode)
+ private static bool IsRedirectCode(HttpStatusCode statusCode) => statusCode switch
{
- switch (statusCode)
- {
- case HttpStatusCode.Moved:
- case HttpStatusCode.Found:
- case HttpStatusCode.SeeOther:
- case HttpStatusCode.TemporaryRedirect:
- case HttpStatusCode.MultipleChoices:
- case HttpStatusCode.PermanentRedirect:
- return true;
- default:
- return false;
- }
- }
+ HttpStatusCode.Moved or
+ HttpStatusCode.Found or
+ HttpStatusCode.SeeOther or
+ HttpStatusCode.TemporaryRedirect or
+ HttpStatusCode.MultipleChoices or
+ HttpStatusCode.PermanentRedirect => true,
+ _ => false,
+ };
// Returns true if the status code is a redirection code and the action requires switching to GET on redirection.
// See https://learn.microsoft.com/en-us/dotnet/api/system.net.httpstatuscode
- private static bool RequestRequiresForceGet(HttpStatusCode statusCode, HttpMethod requestMethod)
+ private static bool RequestRequiresForceGet(HttpStatusCode statusCode, HttpMethod requestMethod) => statusCode switch
{
- switch (statusCode)
- {
- case HttpStatusCode.Moved:
- case HttpStatusCode.Found:
- case HttpStatusCode.MultipleChoices:
- return requestMethod == HttpMethod.Post;
- case HttpStatusCode.SeeOther:
- return requestMethod != HttpMethod.Get && requestMethod != HttpMethod.Head;
- default:
- return false;
- }
- }
+ HttpStatusCode.Moved or
+ HttpStatusCode.Found or
+ HttpStatusCode.MultipleChoices => requestMethod == HttpMethod.Post,
+ HttpStatusCode.SeeOther => requestMethod != HttpMethod.Get && requestMethod != HttpMethod.Head,
+ _ => false,
+ };
// Returns true if the status code shows a server or client error and MaximumRetryCount > 0
- private static bool ShouldRetry(HttpStatusCode statusCode)
+ private static bool ShouldRetry(HttpStatusCode statusCode) => (int)statusCode switch
{
- switch ((int)statusCode)
- {
- case 304:
- case >= 400 and <= 599:
- return true;
- default:
- return false;
- }
- }
+ 304 or (>= 400 and <= 599) => true,
+ _ => false,
+ };
internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestMessage request, bool keepAuthorization)
{
From 3b68566533cb0ca668c3e1d4be004ee8b82ff482 Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Mon, 9 Jan 2023 12:40:21 +0100
Subject: [PATCH 16/27] switch expressions alphabetical order
---
.../WebCmdlet/Common/WebRequestPSCmdlet.Common.cs | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
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 eadb3218c83..b10b9b6423b 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
@@ -1264,12 +1264,12 @@ internal virtual void FillRequestStream(HttpRequestMessage request)
// Returns true if the status code is one of the supported redirection codes.
private static bool IsRedirectCode(HttpStatusCode statusCode) => statusCode switch
{
- HttpStatusCode.Moved or
HttpStatusCode.Found or
- HttpStatusCode.SeeOther or
- HttpStatusCode.TemporaryRedirect or
+ HttpStatusCode.Moved or
HttpStatusCode.MultipleChoices or
- HttpStatusCode.PermanentRedirect => true,
+ HttpStatusCode.PermanentRedirect or
+ HttpStatusCode.SeeOther or
+ HttpStatusCode.TemporaryRedirect => true,
_ => false,
};
@@ -1277,8 +1277,8 @@ HttpStatusCode.MultipleChoices or
// See https://learn.microsoft.com/en-us/dotnet/api/system.net.httpstatuscode
private static bool RequestRequiresForceGet(HttpStatusCode statusCode, HttpMethod requestMethod) => statusCode switch
{
- HttpStatusCode.Moved or
HttpStatusCode.Found or
+ HttpStatusCode.Moved or
HttpStatusCode.MultipleChoices => requestMethod == HttpMethod.Post,
HttpStatusCode.SeeOther => requestMethod != HttpMethod.Get && requestMethod != HttpMethod.Head,
_ => false,
From b7d24f21ddb16331584f8757f4315800343606dc Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Mon, 9 Jan 2023 13:45:44 +0100
Subject: [PATCH 17/27] switch expressions remove last ,
---
.../utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
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 b10b9b6423b..fb543a0bac1 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
@@ -1270,7 +1270,7 @@ HttpStatusCode.MultipleChoices or
HttpStatusCode.PermanentRedirect or
HttpStatusCode.SeeOther or
HttpStatusCode.TemporaryRedirect => true,
- _ => false,
+ _ => false
};
// Returns true if the status code is a redirection code and the action requires switching to GET on redirection.
@@ -1281,14 +1281,14 @@ HttpStatusCode.Found or
HttpStatusCode.Moved or
HttpStatusCode.MultipleChoices => requestMethod == HttpMethod.Post,
HttpStatusCode.SeeOther => requestMethod != HttpMethod.Get && requestMethod != HttpMethod.Head,
- _ => false,
+ _ => false
};
// Returns true if the status code shows a server or client error and MaximumRetryCount > 0
private static bool ShouldRetry(HttpStatusCode statusCode) => (int)statusCode switch
{
304 or (>= 400 and <= 599) => true,
- _ => false,
+ _ => false
};
internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestMessage request, bool keepAuthorization)
From 9ffef1e22a6421bc96296a04d0c73a037036763c Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Fri, 13 Jan 2023 15:00:41 +0100
Subject: [PATCH 18/27] remove spaces
---
.../utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs | 2 +-
1 file changed, 1 insertion(+), 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 a605d0e0e5d..a168aad49ce 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
@@ -1272,7 +1272,7 @@ internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestM
_cancelToken = new CancellationTokenSource();
response = client.SendAsync(req, HttpCompletionOption.ResponseHeadersRead, _cancelToken.Token).GetAwaiter().GetResult();
-
+
if (handleRedirect
&& WebSession.MaximumRedirection is not 0
&& IsRedirectCode(response.StatusCode)
From ef1872278d80b71d54e7df946ff9731f69c93c8a Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Fri, 13 Jan 2023 15:02:08 +0100
Subject: [PATCH 19/27] handleRedirect = PreserveHTTPMethodOnRedirect
---
.../utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs | 2 +-
1 file changed, 1 insertion(+), 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 a168aad49ce..dee83b4fe12 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
@@ -1415,7 +1415,7 @@ protected override void ProcessRecord()
bool keepAuthorizationOnRedirect = PreserveAuthorizationOnRedirect.IsPresent
&& WebSession.Headers.ContainsKey(HttpKnownHeaderNames.Authorization);
- bool handleRedirect = keepAuthorizationOnRedirect || AllowInsecureRedirect;
+ bool handleRedirect = keepAuthorizationOnRedirect || AllowInsecureRedirect || PreserveHTTPMethodOnRedirect;
using (HttpClient client = GetHttpClient(handleRedirect))
{
From 3a29cdc6d94912a3409336d7e7d73f75f88c08f0 Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Fri, 13 Jan 2023 15:02:47 +0100
Subject: [PATCH 20/27] remove spaces
---
.../utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs | 1 -
1 file changed, 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 dee83b4fe12..baf6c1c1a77 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
@@ -963,7 +963,6 @@ internal virtual HttpClient GetHttpClient(bool handleRedirect)
}
// This indicates GetResponse will handle redirects.
-
if (handleRedirect || WebSession.MaximumRedirection == 0)
{
handler.AllowAutoRedirect = false;
From c4533ecb419fbc6e8caec2ccf1010b2a940a9d73 Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Fri, 13 Jan 2023 15:15:02 +0100
Subject: [PATCH 21/27] HTTP -> Http
---
.../utility/WebCmdlet/Common/WebRequestPSCmdlet.Common.cs | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
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 baf6c1c1a77..6a157156a08 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
@@ -287,10 +287,10 @@ public virtual string CustomMethod
private string _custommethod;
///
- /// Gets or sets the PreserveHTTPMethodOnRedirect property.
+ /// Gets or sets the PreserveHttpMethodOnRedirect property.
///
[Parameter]
- public virtual SwitchParameter PreserveHTTPMethodOnRedirect { get; set; }
+ public virtual SwitchParameter PreserveHttpMethodOnRedirect { get; set; }
#endregion
@@ -1287,7 +1287,7 @@ internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestM
}
// For selected redirects, GET must be used with the redirected Location.
- if (RequestRequiresForceGet(response.StatusCode, req.Method) && !PreserveHTTPMethodOnRedirect)
+ if (RequestRequiresForceGet(response.StatusCode, req.Method) && !PreserveHttpMethodOnRedirect)
{
Method = WebRequestMethod.Get;
}
@@ -1414,7 +1414,7 @@ protected override void ProcessRecord()
bool keepAuthorizationOnRedirect = PreserveAuthorizationOnRedirect.IsPresent
&& WebSession.Headers.ContainsKey(HttpKnownHeaderNames.Authorization);
- bool handleRedirect = keepAuthorizationOnRedirect || AllowInsecureRedirect || PreserveHTTPMethodOnRedirect;
+ bool handleRedirect = keepAuthorizationOnRedirect || AllowInsecureRedirect || PreserveHttpMethodOnRedirect;
using (HttpClient client = GetHttpClient(handleRedirect))
{
From a9a67de4d1a7d5d2cece42204d977d1618fc5a88 Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Fri, 13 Jan 2023 23:38:03 +0100
Subject: [PATCH 22/27] add tests
---
.../WebCmdlets.Tests.ps1 | 34 +++++++++++++++++--
1 file changed, 31 insertions(+), 3 deletions(-)
diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1
index 285be044eb4..e641f6e2395 100644
--- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1
+++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1
@@ -893,7 +893,7 @@ Describe "Invoke-WebRequest tests" -Tags "Feature", "RequireAdminOnWindows" {
$response.Error | Should -BeNullOrEmpty
$response.Content.Headers."Authorization" | Should -BeExactly "test"
}
-
+
It "Validates Invoke-WebRequest with -PreserveAuthorizationOnRedirect respects -MaximumRedirection on redirect: " -TestCases $redirectTests {
param($redirectType, $redirectedMethod)
$uri = Get-WebListenerUrl -Test 'Redirect' -TestValue '3' -Query @{type = $redirectType}
@@ -947,12 +947,26 @@ Describe "Invoke-WebRequest tests" -Tags "Feature", "RequireAdminOnWindows" {
$response.Error | Should -BeNullOrEmpty
# ensure user-agent is present (i.e., no false positives )
$response.Content.Headers."User-Agent" | Should -Not -BeNullOrEmpty
- # ensure Authorization header has been removed.
+ # ensure Authorization header has been kept.
$response.Content.Headers."Authorization" | Should -BeExactly 'test'
# ensure POST was changed to GET for selected redirections and remains as POST for others.
$response.Content.Method | Should -Be $redirectedMethod
}
+ It "Validates Invoke-WebRequest -PreserveHttpMethodOnRedirect keeps the authorization header redirects and do remains POST when it handles the redirect: " -TestCases $redirectTests {
+ param($redirectType, $redirectedMethod)
+ $uri = Get-WebListenerUrl -Test 'Redirect' -Query @{type = $redirectType}
+ $response = ExecuteRedirectRequest -PreserveHttpMethodOnRedirect -Uri $uri -Method 'POST'
+
+ $response.Error | Should -BeNullOrEmpty
+ # ensure user-agent is present (i.e., no false positives )
+ $response.Content.Headers."User-Agent" | Should -Not -BeNullOrEmpty
+ # ensure Authorization header has been kept.
+ $response.Content.Headers."Authorization" | Should -BeExactly 'test'
+ # ensure POST doesn't change.
+ $response.Content.Method | Should -Be 'POST'
+ }
+
It "Validates Invoke-WebRequest handles responses without Location header for requests with Authorization header and redirect: " -TestCases $redirectTests {
param($redirectType, $redirectedMethod)
# Skip relative test as it is not a valid response type.
@@ -2641,12 +2655,26 @@ Describe "Invoke-RestMethod tests" -Tags "Feature", "RequireAdminOnWindows" {
$response.Error | Should -BeNullOrEmpty
# ensure user-agent is present (i.e., no false positives )
$response.Content.Headers."User-Agent" | Should -Not -BeNullOrEmpty
- # ensure Authorization header has been removed.
+ # ensure Authorization header has been kept.
$response.Content.Headers."Authorization" | Should -BeExactly 'test'
# ensure POST was changed to GET for selected redirections and remains as POST for others.
$response.Content.Method | Should -Be $redirectedMethod
}
+ It "Validates Invoke-RestMethod -PreserveAuthorizationOnRedirect keeps the authorization header redirects and remains POST when it handles the redirect: " -TestCases $redirectTests {
+ param($redirectType, $redirectedMethod)
+ $uri = Get-WebListenerUrl -Test 'Redirect' -Query @{type = $redirectType}
+ $response = ExecuteRedirectRequest -PreserveAuthorizationOnRedirect -Cmdlet 'Invoke-RestMethod' -Uri $uri -Method 'POST'
+
+ $response.Error | Should -BeNullOrEmpty
+ # ensure user-agent is present (i.e., no false positives )
+ $response.Content.Headers."User-Agent" | Should -Not -BeNullOrEmpty
+ # ensure Authorization header has been kept.
+ $response.Content.Headers."Authorization" | Should -BeExactly 'test'
+ # ensure POST doesn't change.
+ $response.Content.Method | Should -Be 'POST'
+ }
+
It "Validates Invoke-RestMethod handles responses without Location header for requests with Authorization header and redirect: " -TestCases $redirectTests {
param($redirectType, $redirectedMethod)
# Skip relative test as it is not a valid response type.
From 495ad8793f656c7332e7eb04e0ed82474bb98a44 Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Sat, 14 Jan 2023 00:13:07 +0100
Subject: [PATCH 23/27] add PreserveHttpMethodOnRedirect to
ExecuteRedirectRequest
---
.../Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1
index e641f6e2395..4a0ce249b5a 100644
--- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1
+++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1
@@ -135,6 +135,9 @@ function ExecuteRedirectRequest {
[switch]
$PreserveAuthorizationOnRedirect,
+ [switch]
+ $PreserveHttpMethodOnRedirect,
+
[ValidateRange(0, [int]::MaxValue)]
[int]
$MaximumRedirection
@@ -145,13 +148,13 @@ function ExecuteRedirectRequest {
$headers = @{"Authorization" = "test"}
if ($Cmdlet -eq 'Invoke-WebRequest') {
if ($MaximumRedirection -gt 0) {
- $result.Output = Invoke-WebRequest -Uri $uri -Headers $headers -PreserveAuthorizationOnRedirect:$PreserveAuthorizationOnRedirect.IsPresent -Method $Method -MaximumRedirection:$MaximumRedirection
+ $result.Output = Invoke-WebRequest -Uri $uri -Headers $headers -PreserveAuthorizationOnRedirect:$PreserveAuthorizationOnRedirect.IsPresent -PreserveHttpMethodOnRedirect:$PreserveHttpMethodOnRedirect.IsPresent -Method $Method -MaximumRedirection:$MaximumRedirection
} else {
- $result.Output = Invoke-WebRequest -Uri $uri -Headers $headers -PreserveAuthorizationOnRedirect:$PreserveAuthorizationOnRedirect.IsPresent -Method $Method
+ $result.Output = Invoke-WebRequest -Uri $uri -Headers $headers -PreserveAuthorizationOnRedirect:$PreserveAuthorizationOnRedirect.IsPresent -PreserveHttpMethodOnRedirect:$PreserveHttpMethodOnRedirect.IsPresent -Method $Method
}
$result.Content = $result.Output.Content | ConvertFrom-Json
} else {
- $result.Output = Invoke-RestMethod -Uri $uri -Headers $headers -PreserveAuthorizationOnRedirect:$PreserveAuthorizationOnRedirect.IsPresent -Method $Method
+ $result.Output = Invoke-RestMethod -Uri $uri -Headers $headers -PreserveAuthorizationOnRedirect:$PreserveAuthorizationOnRedirect.IsPresent -PreserveHttpMethodOnRedirect:$PreserveHttpMethodOnRedirect.IsPresent -Method $Method
# NOTE: $result.Output should already be a PSObject (Invoke-RestMethod converts the returned json automatically)
# so simply reference $result.Output
$result.Content = $result.Output
From c2000b77a7cb849a7ad643afe76b08fa730ae7c9 Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Sat, 14 Jan 2023 00:51:03 +0100
Subject: [PATCH 24/27] fix tests
---
.../WebCmdlets.Tests.ps1 | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1
index 4a0ce249b5a..b9afdb3bac2 100644
--- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1
+++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1
@@ -379,6 +379,13 @@ $redirectTests = @(
@{redirectType = 'relative'; redirectedMethod = 'GET'}
)
+$redirectTests2 = @(
+ @{redirectType = 'MultipleChoices'}
+ @{redirectType = 'Moved'}
+ @{redirectType = 'Found'}
+ @{redirectType = 'SeeOther'}
+)
+
Describe "Invoke-WebRequest tests" -Tags "Feature", "RequireAdminOnWindows" {
BeforeAll {
$oldProgress = $ProgressPreference
@@ -956,8 +963,8 @@ Describe "Invoke-WebRequest tests" -Tags "Feature", "RequireAdminOnWindows" {
$response.Content.Method | Should -Be $redirectedMethod
}
- It "Validates Invoke-WebRequest -PreserveHttpMethodOnRedirect keeps the authorization header redirects and do remains POST when it handles the redirect: " -TestCases $redirectTests {
- param($redirectType, $redirectedMethod)
+ It "Validates Invoke-WebRequest -PreserveHttpMethodOnRedirect keeps the authorization header redirects and do remains POST when it handles the redirect: " -TestCases $redirectTests2 {
+ param($redirectType)
$uri = Get-WebListenerUrl -Test 'Redirect' -Query @{type = $redirectType}
$response = ExecuteRedirectRequest -PreserveHttpMethodOnRedirect -Uri $uri -Method 'POST'
@@ -2664,10 +2671,10 @@ Describe "Invoke-RestMethod tests" -Tags "Feature", "RequireAdminOnWindows" {
$response.Content.Method | Should -Be $redirectedMethod
}
- It "Validates Invoke-RestMethod -PreserveAuthorizationOnRedirect keeps the authorization header redirects and remains POST when it handles the redirect: " -TestCases $redirectTests {
- param($redirectType, $redirectedMethod)
+ It "Validates Invoke-RestMethod -PreserveHttpMethodOnRedirect keeps the authorization header redirects and remains POST when it handles the redirect: " -TestCases $redirectTests2 {
+ param($redirectType)
$uri = Get-WebListenerUrl -Test 'Redirect' -Query @{type = $redirectType}
- $response = ExecuteRedirectRequest -PreserveAuthorizationOnRedirect -Cmdlet 'Invoke-RestMethod' -Uri $uri -Method 'POST'
+ $response = ExecuteRedirectRequest -PreserveHttpMethodOnRedirect -Cmdlet 'Invoke-RestMethod' -Uri $uri -Method 'POST'
$response.Error | Should -BeNullOrEmpty
# ensure user-agent is present (i.e., no false positives )
From 809cb3f2085e5eab047d812d7fc38aff03148db9 Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Sat, 14 Jan 2023 00:53:07 +0100
Subject: [PATCH 25/27] reverted
---
.../Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)
diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1
index b9afdb3bac2..8f8bc385803 100644
--- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1
+++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1
@@ -379,13 +379,6 @@ $redirectTests = @(
@{redirectType = 'relative'; redirectedMethod = 'GET'}
)
-$redirectTests2 = @(
- @{redirectType = 'MultipleChoices'}
- @{redirectType = 'Moved'}
- @{redirectType = 'Found'}
- @{redirectType = 'SeeOther'}
-)
-
Describe "Invoke-WebRequest tests" -Tags "Feature", "RequireAdminOnWindows" {
BeforeAll {
$oldProgress = $ProgressPreference
@@ -963,7 +956,7 @@ Describe "Invoke-WebRequest tests" -Tags "Feature", "RequireAdminOnWindows" {
$response.Content.Method | Should -Be $redirectedMethod
}
- It "Validates Invoke-WebRequest -PreserveHttpMethodOnRedirect keeps the authorization header redirects and do remains POST when it handles the redirect: " -TestCases $redirectTests2 {
+ It "Validates Invoke-WebRequest -PreserveHttpMethodOnRedirect keeps the authorization header redirects and do remains POST when it handles the redirect: " -TestCases $redirectTests {
param($redirectType)
$uri = Get-WebListenerUrl -Test 'Redirect' -Query @{type = $redirectType}
$response = ExecuteRedirectRequest -PreserveHttpMethodOnRedirect -Uri $uri -Method 'POST'
@@ -2671,7 +2664,7 @@ Describe "Invoke-RestMethod tests" -Tags "Feature", "RequireAdminOnWindows" {
$response.Content.Method | Should -Be $redirectedMethod
}
- It "Validates Invoke-RestMethod -PreserveHttpMethodOnRedirect keeps the authorization header redirects and remains POST when it handles the redirect: " -TestCases $redirectTests2 {
+ It "Validates Invoke-RestMethod -PreserveHttpMethodOnRedirect keeps the authorization header redirects and remains POST when it handles the redirect: " -TestCases $redirectTests {
param($redirectType)
$uri = Get-WebListenerUrl -Test 'Redirect' -Query @{type = $redirectType}
$response = ExecuteRedirectRequest -PreserveHttpMethodOnRedirect -Cmdlet 'Invoke-RestMethod' -Uri $uri -Method 'POST'
From c8aae98c7fb5617fba853ad19509d48c15699683 Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Fri, 10 Feb 2023 10:46:08 +0100
Subject: [PATCH 26/27] merge
---
.../Common/WebRequestPSCmdlet.Common.cs | 938 +++++++++---------
1 file changed, 490 insertions(+), 448 deletions(-)
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 783481147c6..f8a1b1063e7 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
@@ -16,6 +16,8 @@
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
+using System.Text.Json;
+using System.Text.Json.Nodes;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
@@ -86,8 +88,47 @@ public enum WebSslProtocol
///
/// Base class for Invoke-RestMethod and Invoke-WebRequest commands.
///
- public abstract partial class WebRequestPSCmdlet : PSCmdlet
+ public abstract class WebRequestPSCmdlet : PSCmdlet
{
+ #region Fields
+
+ ///
+ /// Cancellation token source.
+ ///
+ internal CancellationTokenSource _cancelToken = null;
+
+ ///
+ /// Automatically follow Rel Links.
+ ///
+ internal bool _followRelLink = false;
+
+ ///
+ /// Maximum number of Rel Links to follow.
+ ///
+ internal int _maximumFollowRelLink = int.MaxValue;
+
+ ///
+ /// Parse Rel Links.
+ ///
+ internal bool _parseRelLink = false;
+
+ ///
+ /// Automatically follow Rel Links.
+ ///
+ internal Dictionary _relationLink = null;
+
+ ///
+ /// The current size of the local file being resumed.
+ ///
+ private long _resumeFileSize = 0;
+
+ ///
+ /// The remote endpoint returned a 206 status code indicating successful resume.
+ ///
+ private bool _resumeSuccess = false;
+
+ #endregion Fields
+
#region Virtual Properties
#region URI
@@ -268,7 +309,7 @@ public abstract partial class WebRequestPSCmdlet : PSCmdlet
/// This property overrides compatibility with web requests on Windows.
/// On FullCLR (WebRequest), authorization headers are stripped during redirect.
/// CoreCLR (HTTPClient) does not have this behavior so web requests that work on
- /// PowerShell/FullCLR can fail with PowerShell/CoreCLR. To provide compatibility,
+ /// PowerShell/FullCLR can fail with PowerShell/CoreCLR. To provide compatibility,
/// we'll detect requests with an Authorization header and automatically strip
/// the header when the first redirect occurs. This switch turns off this logic for
/// edge cases where the authorization header needs to be preserved across redirects.
@@ -429,6 +470,213 @@ public virtual string CustomMethod
#endregion Virtual Properties
+ #region Helper Properties
+
+ internal string QualifiedOutFile => QualifyFilePath(OutFile);
+
+ internal bool ShouldCheckHttpStatus => !SkipHttpErrorCheck;
+
+ ///
+ /// Determines whether writing to a file should Resume and append rather than overwrite.
+ ///
+ internal bool ShouldResume => Resume.IsPresent && _resumeSuccess;
+
+ internal bool ShouldSaveToOutFile => !string.IsNullOrEmpty(OutFile);
+
+ internal bool ShouldWriteToPipeline => !ShouldSaveToOutFile || PassThru;
+
+ #endregion Helper Properties
+
+ #region Abstract Methods
+
+ ///
+ /// Read the supplied WebResponse object and push the resulting output into the pipeline.
+ ///
+ /// Instance of a WebResponse object to be processed.
+ internal abstract void ProcessResponse(HttpResponseMessage response);
+
+ #endregion Abstract Methods
+
+ #region Overrides
+
+ ///
+ /// The main execution method for cmdlets derived from WebRequestPSCmdlet.
+ ///
+ protected override void ProcessRecord()
+ {
+ try
+ {
+ // Set cmdlet context for write progress
+ ValidateParameters();
+ PrepareSession();
+
+ // If the request contains an authorization header and PreserveAuthorizationOnRedirect is not set,
+ // it needs to be stripped on the first redirect.
+ bool keepAuthorizationOnRedirect = PreserveAuthorizationOnRedirect.IsPresent
+ && WebSession.Headers.ContainsKey(HttpKnownHeaderNames.Authorization);
+
+ bool handleRedirect = keepAuthorizationOnRedirect || AllowInsecureRedirect || PreserveHttpMethodOnRedirect;
+
+ using (HttpClient client = GetHttpClient(handleRedirect))
+ {
+ int followedRelLink = 0;
+ Uri uri = Uri;
+ do
+ {
+ if (followedRelLink > 0)
+ {
+ string linkVerboseMsg = string.Format(
+ CultureInfo.CurrentCulture,
+ WebCmdletStrings.FollowingRelLinkVerboseMsg,
+ uri.AbsoluteUri);
+
+ WriteVerbose(linkVerboseMsg);
+ }
+
+ using (HttpRequestMessage request = GetRequest(uri))
+ {
+ FillRequestStream(request);
+ try
+ {
+ long requestContentLength = request.Content is null ? 0 : request.Content.Headers.ContentLength.Value;
+
+ string reqVerboseMsg = string.Format(
+ CultureInfo.CurrentCulture,
+ WebCmdletStrings.WebMethodInvocationVerboseMsg,
+ request.Version,
+ request.Method,
+ requestContentLength);
+
+ WriteVerbose(reqVerboseMsg);
+
+ using HttpResponseMessage response = GetResponse(client, request, handleRedirect);
+
+ string contentType = ContentHelper.GetContentType(response);
+ string respVerboseMsg = string.Format(
+ CultureInfo.CurrentCulture,
+ WebCmdletStrings.WebResponseVerboseMsg,
+ response.Content.Headers.ContentLength,
+ contentType);
+
+ WriteVerbose(respVerboseMsg);
+
+ bool _isSuccess = response.IsSuccessStatusCode;
+
+ // Check if the Resume range was not satisfiable because the file already completed downloading.
+ // This happens when the local file is the same size as the remote file.
+ if (Resume.IsPresent
+ && response.StatusCode == HttpStatusCode.RequestedRangeNotSatisfiable
+ && response.Content.Headers.ContentRange.HasLength
+ && response.Content.Headers.ContentRange.Length == _resumeFileSize)
+ {
+ _isSuccess = true;
+ WriteVerbose(string.Format(
+ CultureInfo.CurrentCulture,
+ WebCmdletStrings.OutFileWritingSkipped,
+ OutFile));
+
+ // Disable writing to the OutFile.
+ OutFile = null;
+ }
+
+ if (ShouldCheckHttpStatus && !_isSuccess)
+ {
+ string message = string.Format(
+ CultureInfo.CurrentCulture,
+ WebCmdletStrings.ResponseStatusCodeFailure,
+ (int)response.StatusCode,
+ response.ReasonPhrase);
+
+ HttpResponseException httpEx = new(message, response);
+ ErrorRecord er = new(httpEx, "WebCmdletWebResponseException", ErrorCategory.InvalidOperation, request);
+ string detailMsg = string.Empty;
+ StreamReader reader = null;
+ try
+ {
+ reader = new StreamReader(StreamHelper.GetResponseStream(response));
+ detailMsg = FormatErrorMessage(reader.ReadToEnd(), contentType);
+ }
+ catch
+ {
+ // Catch all
+ }
+ finally
+ {
+ reader?.Dispose();
+ }
+
+ if (!string.IsNullOrEmpty(detailMsg))
+ {
+ er.ErrorDetails = new ErrorDetails(detailMsg);
+ }
+
+ ThrowTerminatingError(er);
+ }
+
+ if (_parseRelLink || _followRelLink)
+ {
+ ParseLinkHeader(response, uri);
+ }
+
+ ProcessResponse(response);
+ UpdateSession(response);
+
+ // If we hit our maximum redirection count, generate an error.
+ // Errors with redirection counts of greater than 0 are handled automatically by .NET, but are
+ // impossible to detect programmatically when we hit this limit. By handling this ourselves
+ // (and still writing out the result), users can debug actual HTTP redirect problems.
+ if (WebSession.MaximumRedirection == 0 && IsRedirectCode(response.StatusCode))
+ {
+ ErrorRecord er = new(new InvalidOperationException(), "MaximumRedirectExceeded", ErrorCategory.InvalidOperation, request);
+ er.ErrorDetails = new ErrorDetails(WebCmdletStrings.MaximumRedirectionCountExceeded);
+ WriteError(er);
+ }
+ }
+ catch (HttpRequestException ex)
+ {
+ ErrorRecord er = new(ex, "WebCmdletWebResponseException", ErrorCategory.InvalidOperation, request);
+ if (ex.InnerException is not null)
+ {
+ er.ErrorDetails = new ErrorDetails(ex.InnerException.Message);
+ }
+
+ ThrowTerminatingError(er);
+ }
+
+ if (_followRelLink)
+ {
+ if (!_relationLink.ContainsKey("next"))
+ {
+ return;
+ }
+
+ uri = new Uri(_relationLink["next"]);
+ followedRelLink++;
+ }
+ }
+ }
+ while (_followRelLink && (followedRelLink < _maximumFollowRelLink));
+ }
+ }
+ catch (CryptographicException ex)
+ {
+ ErrorRecord er = new(ex, "WebCmdletCertificateException", ErrorCategory.SecurityError, null);
+ ThrowTerminatingError(er);
+ }
+ catch (NotSupportedException ex)
+ {
+ ErrorRecord er = new(ex, "WebCmdletIEDomNotSupportedException", ErrorCategory.NotImplemented, null);
+ ThrowTerminatingError(er);
+ }
+ }
+
+ ///
+ /// To implement ^C.
+ ///
+ protected override void StopProcessing() => _cancelToken?.Cancel();
+
+ #endregion Overrides
+
#region Virtual Methods
internal virtual void ValidateParameters()
@@ -580,24 +828,24 @@ internal virtual void ValidateParameters()
internal virtual void PrepareSession()
{
- // make sure we have a valid WebRequestSession object to work with
+ // Make sure we have a valid WebRequestSession object to work with
WebSession ??= new WebRequestSession();
if (SessionVariable is not null)
{
- // save the session back to the PS environment if requested
+ // Save the session back to the PS environment if requested
PSVariableIntrinsics vi = SessionState.PSVariable;
vi.Set(SessionVariable, WebSession);
}
- // handle credentials
+ // Handle credentials
if (Credential is not null && Authentication == WebAuthenticationType.None)
{
- // get the relevant NetworkCredential
+ // Get the relevant NetworkCredential
NetworkCredential netCred = Credential.GetNetworkCredential();
WebSession.Credentials = netCred;
- // supplying a credential overrides the UseDefaultCredentials setting
+ // Supplying a credential overrides the UseDefaultCredentials setting
WebSession.UseDefaultCredentials = false;
}
else if ((Credential is not null || Token is not null) && Authentication != WebAuthenticationType.None)
@@ -633,10 +881,10 @@ internal virtual void PrepareSession()
WebSession.AddCertificate(Certificate);
}
- // handle the user agent
+ // Handle the user agent
if (UserAgent is not null)
{
- // store the UserAgent string
+ // Store the UserAgent string
WebSession.UserAgent = UserAgent;
}
@@ -663,7 +911,7 @@ internal virtual void PrepareSession()
WebSession.MaximumRedirection = MaximumRedirection;
}
- // store the other supplied headers
+ // Store the other supplied headers
if (Headers is not null)
{
foreach (string key in Headers.Keys)
@@ -689,252 +937,22 @@ internal virtual void PrepareSession()
}
}
- #endregion Virtual Methods
+ internal virtual HttpClient GetHttpClient(bool handleRedirect)
+ {
+ HttpClientHandler handler = new();
+ handler.CookieContainer = WebSession.Cookies;
+ handler.AutomaticDecompression = DecompressionMethods.All;
- #region Helper Properties
-
- internal string QualifiedOutFile => QualifyFilePath(OutFile);
-
- internal bool ShouldSaveToOutFile => !string.IsNullOrEmpty(OutFile);
-
- internal bool ShouldWriteToPipeline => !ShouldSaveToOutFile || PassThru;
-
- internal bool ShouldCheckHttpStatus => !SkipHttpErrorCheck;
-
- ///
- /// Determines whether writing to a file should Resume and append rather than overwrite.
- ///
- internal bool ShouldResume => Resume.IsPresent && _resumeSuccess;
-
- #endregion Helper Properties
-
- #region Helper Methods
- private Uri PrepareUri(Uri uri)
- {
- uri = CheckProtocol(uri);
-
- // Before creating the web request,
- // preprocess Body if content is a dictionary and method is GET (set as query)
- LanguagePrimitives.TryConvertTo(Body, out IDictionary bodyAsDictionary);
- if (bodyAsDictionary is not null && (Method == WebRequestMethod.Default || Method == WebRequestMethod.Get || CustomMethod == "GET"))
- {
- UriBuilder uriBuilder = new(uri);
- if (uriBuilder.Query is not null && uriBuilder.Query.Length > 1)
- {
- uriBuilder.Query = string.Concat(uriBuilder.Query.AsSpan(1), "&", FormatDictionary(bodyAsDictionary));
- }
- else
- {
- uriBuilder.Query = FormatDictionary(bodyAsDictionary);
- }
-
- uri = uriBuilder.Uri;
- // set body to null to prevent later FillRequestStream
- Body = null;
- }
-
- return uri;
- }
-
- private static Uri CheckProtocol(Uri uri)
- {
- ArgumentNullException.ThrowIfNull(uri);
-
- if (!uri.IsAbsoluteUri)
- {
- uri = new Uri("http://" + uri.OriginalString);
- }
-
- return uri;
- }
-
- private string QualifyFilePath(string path)
- {
- string resolvedFilePath = PathUtils.ResolveFilePath(filePath: path, command: this, isLiteralPath: true);
- return resolvedFilePath;
- }
-
- private static string FormatDictionary(IDictionary content)
- {
- ArgumentNullException.ThrowIfNull(content);
-
- StringBuilder bodyBuilder = new();
- foreach (string key in content.Keys)
- {
- if (bodyBuilder.Length > 0)
- {
- bodyBuilder.Append('&');
- }
-
- object value = content[key];
-
- // URLEncode the key and value
- string encodedKey = WebUtility.UrlEncode(key);
- string encodedValue = string.Empty;
- if (value is not null)
- {
- encodedValue = WebUtility.UrlEncode(value.ToString());
- }
-
- bodyBuilder.Append($"{encodedKey}={encodedValue}");
- }
-
- return bodyBuilder.ToString();
- }
-
- private ErrorRecord GetValidationError(string msg, string errorId)
- {
- var ex = new ValidationMetadataException(msg);
- var error = new ErrorRecord(ex, errorId, ErrorCategory.InvalidArgument, this);
- return error;
- }
-
- private ErrorRecord GetValidationError(string msg, string errorId, params object[] args)
- {
- msg = string.Format(CultureInfo.InvariantCulture, msg, args);
- var ex = new ValidationMetadataException(msg);
- var error = new ErrorRecord(ex, errorId, ErrorCategory.InvalidArgument, this);
- return error;
- }
-
- private string GetBasicAuthorizationHeader()
- {
- var password = new NetworkCredential(null, Credential.Password).Password;
- string unencoded = string.Create(CultureInfo.InvariantCulture, $"{Credential.UserName}:{password}");
- byte[] bytes = Encoding.UTF8.GetBytes(unencoded);
- return string.Create(CultureInfo.InvariantCulture, $"Basic {Convert.ToBase64String(bytes)}");
- }
-
- private string GetBearerAuthorizationHeader()
- {
- return string.Create(CultureInfo.InvariantCulture, $"Bearer {new NetworkCredential(string.Empty, Token).Password}");
- }
-
- private void ProcessAuthentication()
- {
- if (Authentication == WebAuthenticationType.Basic)
- {
- WebSession.Headers["Authorization"] = GetBasicAuthorizationHeader();
- }
- else if (Authentication == WebAuthenticationType.Bearer || Authentication == WebAuthenticationType.OAuth)
- {
- WebSession.Headers["Authorization"] = GetBearerAuthorizationHeader();
- }
- else
- {
- Diagnostics.Assert(false, string.Create(CultureInfo.InvariantCulture, $"Unrecognized Authentication value: {Authentication}"));
- }
- }
-
- #endregion Helper Methods
- }
-
- // TODO: Merge Partials
-
- ///
- /// Exception class for webcmdlets to enable returning HTTP error response.
- ///
- public sealed class HttpResponseException : HttpRequestException
- {
- ///
- /// Initializes a new instance of the class.
- ///
- /// Message for the exception.
- /// Response from the HTTP server.
- public HttpResponseException(string message, HttpResponseMessage response) : base(message, inner: null, response.StatusCode)
- {
- Response = response;
- }
-
- ///
- /// HTTP error response.
- ///
- public HttpResponseMessage Response { get; }
- }
-
- ///
- /// Base class for Invoke-RestMethod and Invoke-WebRequest commands.
- ///
- public abstract partial class WebRequestPSCmdlet : PSCmdlet
- {
- #region Abstract Methods
-
- ///
- /// Read the supplied WebResponse object and push the resulting output into the pipeline.
- ///
- /// Instance of a WebResponse object to be processed.
- internal abstract void ProcessResponse(HttpResponseMessage response);
-
- #endregion Abstract Methods
-
- ///
- /// Cancellation token source.
- ///
- internal CancellationTokenSource _cancelToken = null;
-
- ///
- /// Parse Rel Links.
- ///
- internal bool _parseRelLink = false;
-
- ///
- /// Automatically follow Rel Links.
- ///
- internal bool _followRelLink = false;
-
- ///
- /// Automatically follow Rel Links.
- ///
- internal Dictionary _relationLink = null;
-
- ///
- /// Maximum number of Rel Links to follow.
- ///
- internal int _maximumFollowRelLink = int.MaxValue;
-
- ///
- /// The remote endpoint returned a 206 status code indicating successful resume.
- ///
- private bool _resumeSuccess = false;
-
- ///
- /// The current size of the local file being resumed.
- ///
- private long _resumeFileSize = 0;
-
- private static HttpMethod GetHttpMethod(WebRequestMethod method) => method switch
- {
- WebRequestMethod.Default or WebRequestMethod.Get => HttpMethod.Get,
- WebRequestMethod.Delete => HttpMethod.Delete,
- WebRequestMethod.Head => HttpMethod.Head,
- WebRequestMethod.Patch => HttpMethod.Patch,
- WebRequestMethod.Post => HttpMethod.Post,
- WebRequestMethod.Put => HttpMethod.Put,
- WebRequestMethod.Options => HttpMethod.Options,
- WebRequestMethod.Trace => HttpMethod.Trace,
- _ => new HttpMethod(method.ToString().ToUpperInvariant())
- };
-
- #region Virtual Methods
-
- // NOTE: Only pass true for handleRedirect if the original request has an authorization header
- // and PreserveAuthorizationOnRedirect is NOT set.
- internal virtual HttpClient GetHttpClient(bool handleRedirect)
- {
- HttpClientHandler handler = new();
- handler.CookieContainer = WebSession.Cookies;
- handler.AutomaticDecompression = DecompressionMethods.All;
-
- // set the credentials used by this request
- if (WebSession.UseDefaultCredentials)
- {
- // the UseDefaultCredentials flag overrides other supplied credentials
- handler.UseDefaultCredentials = true;
- }
- else if (WebSession.Credentials is not null)
- {
- handler.Credentials = WebSession.Credentials;
- }
+ // Set the credentials used by this request
+ if (WebSession.UseDefaultCredentials)
+ {
+ // The UseDefaultCredentials flag overrides other supplied credentials
+ handler.UseDefaultCredentials = true;
+ }
+ else if (WebSession.Credentials is not null)
+ {
+ handler.Credentials = WebSession.Credentials;
+ }
if (NoProxy)
{
@@ -981,7 +999,7 @@ internal virtual HttpRequestMessage GetRequest(Uri uri)
Uri requestUri = PrepareUri(uri);
HttpMethod httpMethod = string.IsNullOrEmpty(CustomMethod) ? GetHttpMethod(Method) : new HttpMethod(CustomMethod);
- // create the base WebRequest object
+ // Create the base WebRequest object
var request = new HttpRequestMessage(httpMethod, requestUri);
if (HttpVersion is not null)
@@ -989,7 +1007,7 @@ internal virtual HttpRequestMessage GetRequest(Uri uri)
request.Version = HttpVersion;
}
- // pull in session data
+ // Pull in session data
if (WebSession.Headers.Count > 0)
{
WebSession.ContentHeaders.Clear();
@@ -1076,13 +1094,11 @@ internal virtual void FillRequestStream(HttpRequestMessage request)
{
ArgumentNullException.ThrowIfNull(request);
- // set the content type
+ // Set the request content type
if (ContentType is not null)
{
WebSession.ContentHeaders[HttpKnownHeaderNames.ContentType] = ContentType;
- // request
}
- // ContentType is null
else if (request.Method == HttpMethod.Post)
{
// Win8:545310 Invoke-WebRequest does not properly set MIME type for POST
@@ -1194,36 +1210,6 @@ internal virtual void FillRequestStream(HttpRequestMessage request)
}
}
- // Returns true if the status code is one of the supported redirection codes.
- private static bool IsRedirectCode(HttpStatusCode statusCode) => statusCode switch
- {
- HttpStatusCode.Found or
- HttpStatusCode.Moved or
- HttpStatusCode.MultipleChoices or
- HttpStatusCode.PermanentRedirect or
- HttpStatusCode.SeeOther or
- HttpStatusCode.TemporaryRedirect => true,
- _ => false
- };
-
- // Returns true if the status code is a redirection code and the action requires switching to GET on redirection.
- // See https://learn.microsoft.com/en-us/dotnet/api/system.net.httpstatuscode
- private static bool RequestRequiresForceGet(HttpStatusCode statusCode, HttpMethod requestMethod) => statusCode switch
- {
- HttpStatusCode.Found or
- HttpStatusCode.Moved or
- HttpStatusCode.MultipleChoices => requestMethod == HttpMethod.Post,
- HttpStatusCode.SeeOther => requestMethod != HttpMethod.Get && requestMethod != HttpMethod.Head,
- _ => false
- };
-
- // Returns true if the status code shows a server or client error and MaximumRetryCount > 0
- private static bool ShouldRetry(HttpStatusCode statusCode) => (int)statusCode switch
- {
- 304 or (>= 400 and <= 599) => true,
- _ => false
- };
-
internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestMessage request, bool handleRedirect)
{
ArgumentNullException.ThrowIfNull(client);
@@ -1266,6 +1252,7 @@ internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestM
// Continue to handle redirection
using HttpRequestMessage redirectRequest = GetRequest(currentUri);
+ response.Dispose();
response = GetResponse(client, redirectRequest, handleRedirect);
}
@@ -1300,7 +1287,8 @@ internal virtual HttpResponseMessage GetResponse(HttpClient client, HttpRequestM
WriteVerbose(reqVerboseMsg);
- return GetResponse(client, requestWithoutRange, handleRedirect);
+ response.Dispose();
+ response = GetResponse(client, requestWithoutRange, handleRedirect);
}
}
@@ -1361,190 +1349,125 @@ internal virtual void UpdateSession(HttpResponseMessage response)
#endregion Virtual Methods
- #region Overrides
-
- ///
- /// The main execution method for cmdlets derived from WebRequestPSCmdlet.
- ///
- protected override void ProcessRecord()
+ #region Helper Methods
+ private Uri PrepareUri(Uri uri)
{
- try
- {
- // Set cmdlet context for write progress
- ValidateParameters();
- PrepareSession();
-
- // If the request contains an authorization header and PreserveAuthorizationOnRedirect is not set,
- // it needs to be stripped on the first redirect.
- bool keepAuthorizationOnRedirect = PreserveAuthorizationOnRedirect.IsPresent
- && WebSession.Headers.ContainsKey(HttpKnownHeaderNames.Authorization);
-
- bool handleRedirect = keepAuthorizationOnRedirect || AllowInsecureRedirect || PreserveHttpMethodOnRedirect;
+ uri = CheckProtocol(uri);
- using (HttpClient client = GetHttpClient(handleRedirect))
+ // Before creating the web request,
+ // preprocess Body if content is a dictionary and method is GET (set as query)
+ LanguagePrimitives.TryConvertTo(Body, out IDictionary bodyAsDictionary);
+ if (bodyAsDictionary is not null && (Method == WebRequestMethod.Default || Method == WebRequestMethod.Get || CustomMethod == "GET"))
+ {
+ UriBuilder uriBuilder = new(uri);
+ if (uriBuilder.Query is not null && uriBuilder.Query.Length > 1)
{
- int followedRelLink = 0;
- Uri uri = Uri;
- do
- {
- if (followedRelLink > 0)
- {
- string linkVerboseMsg = string.Format(
- CultureInfo.CurrentCulture,
- WebCmdletStrings.FollowingRelLinkVerboseMsg,
- uri.AbsoluteUri);
-
- WriteVerbose(linkVerboseMsg);
- }
-
- using (HttpRequestMessage request = GetRequest(uri))
- {
- FillRequestStream(request);
- try
- {
- long requestContentLength = request.Content is null ? 0 : request.Content.Headers.ContentLength.Value;
-
- string reqVerboseMsg = string.Format(
- CultureInfo.CurrentCulture,
- WebCmdletStrings.WebMethodInvocationVerboseMsg,
- request.Version,
- request.Method,
- requestContentLength);
+ uriBuilder.Query = string.Concat(uriBuilder.Query.AsSpan(1), "&", FormatDictionary(bodyAsDictionary));
+ }
+ else
+ {
+ uriBuilder.Query = FormatDictionary(bodyAsDictionary);
+ }
- WriteVerbose(reqVerboseMsg);
+ uri = uriBuilder.Uri;
- HttpResponseMessage response = GetResponse(client, request, handleRedirect);
+ // Set body to null to prevent later FillRequestStream
+ Body = null;
+ }
- string contentType = ContentHelper.GetContentType(response);
- string respVerboseMsg = string.Format(
- CultureInfo.CurrentCulture,
- WebCmdletStrings.WebResponseVerboseMsg,
- response.Content.Headers.ContentLength,
- contentType);
+ return uri;
+ }
- WriteVerbose(respVerboseMsg);
+ private static Uri CheckProtocol(Uri uri)
+ {
+ ArgumentNullException.ThrowIfNull(uri);
- bool _isSuccess = response.IsSuccessStatusCode;
+ if (!uri.IsAbsoluteUri)
+ {
+ uri = new Uri("http://" + uri.OriginalString);
+ }
- // Check if the Resume range was not satisfiable because the file already completed downloading.
- // This happens when the local file is the same size as the remote file.
- if (Resume.IsPresent
- && response.StatusCode == HttpStatusCode.RequestedRangeNotSatisfiable
- && response.Content.Headers.ContentRange.HasLength
- && response.Content.Headers.ContentRange.Length == _resumeFileSize)
- {
- _isSuccess = true;
- WriteVerbose(string.Format(
- CultureInfo.CurrentCulture,
- WebCmdletStrings.OutFileWritingSkipped,
- OutFile));
+ return uri;
+ }
- // Disable writing to the OutFile.
- OutFile = null;
- }
+ private string QualifyFilePath(string path)
+ {
+ string resolvedFilePath = PathUtils.ResolveFilePath(filePath: path, command: this, isLiteralPath: true);
+ return resolvedFilePath;
+ }
- if (ShouldCheckHttpStatus && !_isSuccess)
- {
- string message = string.Format(
- CultureInfo.CurrentCulture,
- WebCmdletStrings.ResponseStatusCodeFailure,
- (int)response.StatusCode,
- response.ReasonPhrase);
+ private static string FormatDictionary(IDictionary content)
+ {
+ ArgumentNullException.ThrowIfNull(content);
- HttpResponseException httpEx = new(message, response);
- ErrorRecord er = new(httpEx, "WebCmdletWebResponseException", ErrorCategory.InvalidOperation, request);
- string detailMsg = string.Empty;
- StreamReader reader = null;
- try
- {
- reader = new(StreamHelper.GetResponseStream(response));
+ StringBuilder bodyBuilder = new();
+ foreach (string key in content.Keys)
+ {
+ if (bodyBuilder.Length > 0)
+ {
+ bodyBuilder.Append('&');
+ }
- // Remove HTML tags making it easier to read
- detailMsg = System.Text.RegularExpressions.Regex.Replace(reader.ReadToEnd(), "<[^>]*>", string.Empty);
- }
- catch
- {
- // Catch all
- }
- finally
- {
- reader?.Dispose();
- }
+ object value = content[key];
- if (!string.IsNullOrEmpty(detailMsg))
- {
- er.ErrorDetails = new ErrorDetails(detailMsg);
- }
+ // URLEncode the key and value
+ string encodedKey = WebUtility.UrlEncode(key);
+ string encodedValue = string.Empty;
+ if (value is not null)
+ {
+ encodedValue = WebUtility.UrlEncode(value.ToString());
+ }
- ThrowTerminatingError(er);
- }
+ bodyBuilder.Append($"{encodedKey}={encodedValue}");
+ }
- if (_parseRelLink || _followRelLink)
- {
- ParseLinkHeader(response, uri);
- }
+ return bodyBuilder.ToString();
+ }
- ProcessResponse(response);
- UpdateSession(response);
+ private ErrorRecord GetValidationError(string msg, string errorId)
+ {
+ var ex = new ValidationMetadataException(msg);
+ var error = new ErrorRecord(ex, errorId, ErrorCategory.InvalidArgument, this);
+ return error;
+ }
- // If we hit our maximum redirection count, generate an error.
- // Errors with redirection counts of greater than 0 are handled automatically by .NET, but are
- // impossible to detect programmatically when we hit this limit. By handling this ourselves
- // (and still writing out the result), users can debug actual HTTP redirect problems.
- if (WebSession.MaximumRedirection == 0 && IsRedirectCode(response.StatusCode)) // Indicate "HttpClientHandler.AllowAutoRedirect is false"
- {
- ErrorRecord er = new(new InvalidOperationException(), "MaximumRedirectExceeded", ErrorCategory.InvalidOperation, request);
- er.ErrorDetails = new ErrorDetails(WebCmdletStrings.MaximumRedirectionCountExceeded);
- WriteError(er);
- }
- }
- catch (HttpRequestException ex)
- {
- ErrorRecord er = new(ex, "WebCmdletWebResponseException", ErrorCategory.InvalidOperation, request);
- if (ex.InnerException is not null)
- {
- er.ErrorDetails = new ErrorDetails(ex.InnerException.Message);
- }
+ private ErrorRecord GetValidationError(string msg, string errorId, params object[] args)
+ {
+ msg = string.Format(CultureInfo.InvariantCulture, msg, args);
+ var ex = new ValidationMetadataException(msg);
+ var error = new ErrorRecord(ex, errorId, ErrorCategory.InvalidArgument, this);
+ return error;
+ }
- ThrowTerminatingError(er);
- }
+ private string GetBasicAuthorizationHeader()
+ {
+ var password = new NetworkCredential(null, Credential.Password).Password;
+ string unencoded = string.Create(CultureInfo.InvariantCulture, $"{Credential.UserName}:{password}");
+ byte[] bytes = Encoding.UTF8.GetBytes(unencoded);
+ return string.Create(CultureInfo.InvariantCulture, $"Basic {Convert.ToBase64String(bytes)}");
+ }
- if (_followRelLink)
- {
- if (!_relationLink.ContainsKey("next"))
- {
- return;
- }
+ private string GetBearerAuthorizationHeader()
+ {
+ return string.Create(CultureInfo.InvariantCulture, $"Bearer {new NetworkCredential(string.Empty, Token).Password}");
+ }
- uri = new Uri(_relationLink["next"]);
- followedRelLink++;
- }
- }
- }
- while (_followRelLink && (followedRelLink < _maximumFollowRelLink));
- }
+ private void ProcessAuthentication()
+ {
+ if (Authentication == WebAuthenticationType.Basic)
+ {
+ WebSession.Headers["Authorization"] = GetBasicAuthorizationHeader();
}
- catch (CryptographicException ex)
+ else if (Authentication == WebAuthenticationType.Bearer || Authentication == WebAuthenticationType.OAuth)
{
- ErrorRecord er = new(ex, "WebCmdletCertificateException", ErrorCategory.SecurityError, null);
- ThrowTerminatingError(er);
+ WebSession.Headers["Authorization"] = GetBearerAuthorizationHeader();
}
- catch (NotSupportedException ex)
+ else
{
- ErrorRecord er = new(ex, "WebCmdletIEDomNotSupportedException", ErrorCategory.NotImplemented, null);
- ThrowTerminatingError(er);
+ Diagnostics.Assert(false, string.Create(CultureInfo.InvariantCulture, $"Unrecognized Authentication value: {Authentication}"));
}
}
- ///
- /// To implement ^C.
- ///
- protected override void StopProcessing() => _cancelToken?.Cancel();
-
- #endregion Overrides
-
- #region Helper Methods
-
///
/// Sets the ContentLength property of the request and writes the specified content to the request's RequestStream.
///
@@ -1719,7 +1642,7 @@ internal void ParseLinkHeader(HttpResponseMessage response, System.Uri requestUr
///
/// The Field Name to use.
/// The Field Value to use.
- /// The > to update.
+ /// The to update.
/// If true, collection types in will be enumerated. If false, collections will be treated as single value.
private void AddMultipartContent(object fieldName, object fieldValue, MultipartFormDataContent formData, bool enumerate)
{
@@ -1810,11 +1733,130 @@ private static StreamContent GetMultipartStreamContent(object fieldName, Stream
private static StreamContent GetMultipartFileContent(object fieldName, FileInfo file)
{
var result = GetMultipartStreamContent(fieldName: fieldName, stream: new FileStream(file.FullName, FileMode.Open));
+
// .NET does not enclose field names in quotes, however, modern browsers and curl do.
result.Headers.ContentDisposition.FileName = "\"" + file.Name + "\"";
return result;
}
+
+ private static string FormatErrorMessage(string error, string contentType)
+ {
+ string formattedError = null;
+
+ try
+ {
+ if (ContentHelper.IsXml(contentType))
+ {
+ XmlDocument doc = new();
+ doc.LoadXml(error);
+
+ XmlWriterSettings settings = new XmlWriterSettings {
+ Indent = true,
+ NewLineOnAttributes = true,
+ OmitXmlDeclaration = true
+ };
+
+ if (doc.FirstChild is XmlDeclaration)
+ {
+ XmlDeclaration decl = doc.FirstChild as XmlDeclaration;
+ settings.Encoding = Encoding.GetEncoding(decl.Encoding);
+ }
+
+ StringBuilder stringBuilder = new();
+ using XmlWriter xmlWriter = XmlWriter.Create(stringBuilder, settings);
+ doc.Save(xmlWriter);
+ string xmlString = stringBuilder.ToString();
+
+ formattedError = Environment.NewLine + xmlString;
+ }
+ else if (ContentHelper.IsJson(contentType))
+ {
+ JsonNode jsonNode = JsonNode.Parse(error);
+ JsonSerializerOptions options = new JsonSerializerOptions { WriteIndented = true };
+ string jsonString = jsonNode.ToJsonString(options);
+
+ formattedError = Environment.NewLine + jsonString;
+ }
+ }
+ catch
+ {
+ // Ignore errors
+ }
+
+ if (string.IsNullOrEmpty(formattedError))
+ {
+ // Remove HTML tags making it easier to read
+ formattedError = System.Text.RegularExpressions.Regex.Replace(error, "<[^>]*>", string.Empty);
+ }
+
+ return formattedError;
+ }
+
+ // Returns true if the status code is one of the supported redirection codes.
+ private static bool IsRedirectCode(HttpStatusCode statusCode) => statusCode switch
+ {
+ HttpStatusCode.Found or
+ HttpStatusCode.Moved or
+ HttpStatusCode.MultipleChoices or
+ HttpStatusCode.PermanentRedirect or
+ HttpStatusCode.SeeOther or
+ HttpStatusCode.TemporaryRedirect => true,
+ _ => false
+ };
+
+ // Returns true if the status code is a redirection code and the action requires switching to GET on redirection.
+ // See https://learn.microsoft.com/en-us/dotnet/api/system.net.httpstatuscode
+ private static bool RequestRequiresForceGet(HttpStatusCode statusCode, HttpMethod requestMethod) => statusCode switch
+ {
+ HttpStatusCode.Found or
+ HttpStatusCode.Moved or
+ HttpStatusCode.MultipleChoices => requestMethod == HttpMethod.Post,
+ HttpStatusCode.SeeOther => requestMethod != HttpMethod.Get && requestMethod != HttpMethod.Head,
+ _ => false
+ };
+
+ // Returns true if the status code shows a server or client error and MaximumRetryCount > 0
+ private static bool ShouldRetry(HttpStatusCode statusCode) => (int)statusCode switch
+ {
+ 304 or (>= 400 and <= 599) => true,
+ _ => false
+ };
+
+ private static HttpMethod GetHttpMethod(WebRequestMethod method) => method switch
+ {
+ WebRequestMethod.Default or WebRequestMethod.Get => HttpMethod.Get,
+ WebRequestMethod.Delete => HttpMethod.Delete,
+ WebRequestMethod.Head => HttpMethod.Head,
+ WebRequestMethod.Patch => HttpMethod.Patch,
+ WebRequestMethod.Post => HttpMethod.Post,
+ WebRequestMethod.Put => HttpMethod.Put,
+ WebRequestMethod.Options => HttpMethod.Options,
+ WebRequestMethod.Trace => HttpMethod.Trace,
+ _ => new HttpMethod(method.ToString().ToUpperInvariant())
+ };
+
#endregion Helper Methods
}
+
+ ///
+ /// Exception class for webcmdlets to enable returning HTTP error response.
+ ///
+ public sealed class HttpResponseException : HttpRequestException
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Message for the exception.
+ /// Response from the HTTP server.
+ public HttpResponseException(string message, HttpResponseMessage response) : base(message, inner: null, response.StatusCode)
+ {
+ Response = response;
+ }
+
+ ///
+ /// HTTP error response.
+ ///
+ public HttpResponseMessage Response { get; }
+ }
}
From c91c8f3ee1fdf1e45b95bcd887faf72fa29cddbf Mon Sep 17 00:00:00 2001
From: CarloToso <105941898+CarloToso@users.noreply.github.com>
Date: Tue, 14 Feb 2023 10:06:29 +0100
Subject: [PATCH 27/27] moved or
---
.../Common/WebRequestPSCmdlet.Common.cs | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
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 61e331e5ad7..567a98ebfb9 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
@@ -1780,12 +1780,12 @@ private static string FormatErrorMessage(string error, string contentType)
// Returns true if the status code is one of the supported redirection codes.
private static bool IsRedirectCode(HttpStatusCode statusCode) => statusCode switch
{
- HttpStatusCode.Found or
- HttpStatusCode.Moved or
- HttpStatusCode.MultipleChoices or
- HttpStatusCode.PermanentRedirect or
- HttpStatusCode.SeeOther or
- HttpStatusCode.TemporaryRedirect => true,
+ HttpStatusCode.Found
+ or HttpStatusCode.Moved
+ or HttpStatusCode.MultipleChoices
+ or HttpStatusCode.PermanentRedirect
+ or HttpStatusCode.SeeOther
+ or HttpStatusCode.TemporaryRedirect => true,
_ => false
};
@@ -1793,9 +1793,9 @@ HttpStatusCode.SeeOther or
// See https://learn.microsoft.com/en-us/dotnet/api/system.net.httpstatuscode
private static bool RequestRequiresForceGet(HttpStatusCode statusCode, HttpMethod requestMethod) => statusCode switch
{
- HttpStatusCode.Found or
- HttpStatusCode.Moved or
- HttpStatusCode.MultipleChoices => requestMethod == HttpMethod.Post,
+ HttpStatusCode.Found
+ or HttpStatusCode.Moved
+ or HttpStatusCode.MultipleChoices => requestMethod == HttpMethod.Post,
HttpStatusCode.SeeOther => requestMethod != HttpMethod.Get && requestMethod != HttpMethod.Head,
_ => false
};