diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebRequestPSCmdlet.CoreClr.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebRequestPSCmdlet.CoreClr.cs
index 23d35548774..bbe96fa6641 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebRequestPSCmdlet.CoreClr.cs
+++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/WebCmdlet/CoreCLR/WebRequestPSCmdlet.CoreClr.cs
@@ -58,12 +58,21 @@ public abstract partial class WebRequestPSCmdlet : PSCmdlet
/// CoreCLR (HTTPClient) does not have this behavior so web requests that work on
/// 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
+ /// 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.
///
[Parameter]
public virtual SwitchParameter PreserveAuthorizationOnRedirect { get; set; }
+ ///
+ /// gets or sets the SkipHeaderValidation property
+ ///
+ ///
+ /// This property adds headers to the request's header collection without validation.
+ ///
+ [Parameter]
+ public virtual SwitchParameter SkipHeaderValidation { get; set; }
+
#region Abstract Methods
///
@@ -240,14 +249,22 @@ internal virtual HttpRequestMessage GetRequest(Uri uri, bool stripAuthorization)
}
else
{
- if (stripAuthorization
- &&
+ if (stripAuthorization
+ &&
String.Equals(entry.Key, HttpKnownHeaderNames.Authorization.ToString(), StringComparison.OrdinalIgnoreCase)
)
{
continue;
}
- request.Headers.Add(entry.Key, entry.Value);
+
+ if (SkipHeaderValidation)
+ {
+ request.Headers.TryAddWithoutValidation(entry.Key, entry.Value);
+ }
+ else
+ {
+ request.Headers.Add(entry.Key, entry.Value);
+ }
}
}
}
diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1
index 92108dc31d2..4f01f9790b3 100644
--- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1
+++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1
@@ -184,6 +184,49 @@ function ExecuteRedirectRequest
return $result
}
+# This function calls either Invoke-WebRequest or Invoke-RestMethod with the given uri
+# using the custum headers and the optional SkipHeaderValidation switch.
+function ExecuteRequestWithCustomHeaders
+{
+ param (
+ [Parameter(Mandatory)]
+ [string]
+ $Uri,
+
+ [ValidateSet('Invoke-WebRequest', 'Invoke-RestMethod')]
+ [string] $Cmdlet = 'Invoke-WebRequest',
+
+ [Parameter(Mandatory)]
+ [ValidateNotNull()]
+ [Hashtable] $Headers,
+
+ [switch] $SkipHeaderValidation
+ )
+ $result = [PSObject]@{Output = $null; Error = $null; Content = $null}
+
+ try
+ {
+ if ($Cmdlet -eq 'Invoke-WebRequest')
+ {
+ $result.Output = Invoke-WebRequest -Uri $Uri -TimeoutSec 5 -Headers $Headers -SkipHeaderValidation:$SkipHeaderValidation.IsPresent
+ $result.Content = $result.Output.Content | ConvertFrom-Json
+ }
+ else
+ {
+ $result.Output = Invoke-RestMethod -Uri $Uri -TimeoutSec 5 -Headers $Headers -SkipHeaderValidation:$SkipHeaderValidation.IsPresent
+ # NOTE: $result.Output should already be a PSObject (Invoke-RestMethod converts the returned json automatically)
+ # so simply reference $result.Output
+ $result.Content = $result.Output
+ }
+ }
+ catch
+ {
+ $result.Error = $_
+ }
+
+ return $result
+}
+
<#
Defines the list of redirect codes to test as well as the
expected Method when the redirection is handled.
@@ -662,6 +705,35 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" {
#endregion Redirect tests
+ #region SkipHeaderVerification Tests
+
+ It "Verifies Invoke-WebRequest default header handling with no errors" {
+ $headers = @{"If-Match" = "*"}
+ $response = ExecuteRequestWithCustomHeaders -Uri "http://localhost:8080/PowerShell?test=echo" -headers $headers
+
+ $response.Error | Should BeNullOrEmpty
+ $response.Content.Headers -contains "If-Match" | Should Be $true
+ }
+
+ It "Verifies Invoke-WebRequest default header handling reports an error is returned for an invalid If-Match header value" {
+ $headers = @{"If-Match" = "12345"}
+ $response = ExecuteRequestWithCustomHeaders -Uri "http://localhost:8080/PowerShell?test=echo" -headers $headers
+
+ $response.Error | Should Not BeNullOrEmpty
+ $response.Error.FullyQualifiedErrorId | Should Be "System.FormatException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand"
+ $response.Error.Exception.Message | Should Be "The format of value '12345' is invalid."
+ }
+
+ It "Verifies Invoke-WebRequest header handling does not report an error when using -SkipHeaderValidation" {
+ $headers = @{"If-Match" = "12345"}
+ $response = ExecuteRequestWithCustomHeaders -Uri "http://localhost:8080/PowerShell?test=echo" -headers $headers -SkipHeaderValidation
+
+ $response.Error | Should BeNullOrEmpty
+ $response.Content.Headers -contains "If-Match" | Should Be $true
+ }
+
+ #endregion SkipHeaderVerification Tests
+
BeforeEach {
if ($env:http_proxy) {
$savedHttpProxy = $env:http_proxy
@@ -1124,6 +1196,35 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" {
#endregion Redirect tests
+ #region SkipHeaderVerification tests
+
+ It "Verifies Invoke-RestMethod default header handling with no errors" {
+ $headers = @{"If-Match" = "*"}
+ $response = ExecuteRequestWithCustomHeaders -Uri "http://localhost:8081/PowerShell?test=echo" -headers $headers -Cmdlet "Invoke-RestMethod"
+
+ $response.Error | Should BeNullOrEmpty
+ $response.Content.Headers -contains "If-Match" | Should Be $true
+ }
+
+ It "Verifies Invoke-RestMethod default header handling reports an error is returned for an invalid If-Match header value" {
+ $headers = @{"If-Match" = "12345"}
+ $response = ExecuteRequestWithCustomHeaders -Uri "http://localhost:8081/PowerShell?test=echo" -headers $headers -Cmdlet "Invoke-RestMethod"
+
+ $response.Error | Should Not BeNullOrEmpty
+ $response.Error.FullyQualifiedErrorId | Should Be "System.FormatException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand"
+ $response.Error.Exception.Message | Should Be "The format of value '12345' is invalid."
+ }
+
+ It "Verifies Invoke-RestMethod header handling does not report an error when using -SkipHeaderValidation" {
+ $headers = @{"If-Match" = "12345"}
+ $response = ExecuteRequestWithCustomHeaders -Uri "http://localhost:8081/PowerShell?test=echo" -headers $headers -SkipHeaderValidation -Cmdlet "Invoke-RestMethod"
+
+ $response.Error | Should BeNullOrEmpty
+ $response.Content.Headers -contains "If-Match" | Should Be $true
+ }
+
+ #endregion SkipHeaderVerification tests
+
BeforeEach {
if ($env:http_proxy) {
$savedHttpProxy = $env:http_proxy
diff --git a/test/tools/Modules/HttpListener/HttpListener.psm1 b/test/tools/Modules/HttpListener/HttpListener.psm1
index e38afff1385..358179d37bf 100644
--- a/test/tools/Modules/HttpListener/HttpListener.psm1
+++ b/test/tools/Modules/HttpListener/HttpListener.psm1
@@ -134,6 +134,13 @@ Function Start-HTTPListener {
$contentType = $queryItems["contenttype"]
$output = $queryItems["output"]
}
+
+ # Echo the request as the output.
+ "echo"
+ {
+ Write-Verbose -Message "Echo request"
+ $output = $request | ConvertTo-Json -Depth 6
+ }
<#
This test provides support for multiple redirection types as well as a custom