From c90eea629f640094434de5547d98f2b2ae587be0 Mon Sep 17 00:00:00 2001 From: Mark Kraus Date: Wed, 24 Jan 2018 04:39:06 -0600 Subject: [PATCH 1/5] [feature] Add SkipHeaderValidation Support to ContentType on Web Cmdlets --- .../Common/WebRequestPSCmdlet.Common.cs | 28 +++++++++++++++---- 1 file changed, 23 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 748732d7c6b..1d6c8848d0a 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 @@ -1176,7 +1176,14 @@ internal virtual void FillRequestStream(HttpRequestMessage request) { foreach (var entry in WebSession.ContentHeaders) { - request.Content.Headers.Add(entry.Key, entry.Value); + if (SkipHeaderValidation) + { + request.Content.Headers.TryAddWithoutValidation(entry.Key, entry.Value); + } + else + { + request.Content.Headers.Add(entry.Key, entry.Value); + } } } } @@ -1476,14 +1483,25 @@ internal long SetRequestContent(HttpRequestMessage request, string content) // If Content-Type contains the encoding format (as CharSet), use this encoding format // to encode the Body of the WebRequest sent to the server. Default Encoding format // would be used if Charset is not supplied in the Content-Type property. - var mediaTypeHeaderValue = new MediaTypeHeaderValue(ContentType); - if (!string.IsNullOrEmpty(mediaTypeHeaderValue.CharSet)) + try { - try + var mediaTypeHeaderValue = new MediaTypeHeaderValue(ContentType); + if (!string.IsNullOrEmpty(mediaTypeHeaderValue.CharSet)) { encoding = Encoding.GetEncoding(mediaTypeHeaderValue.CharSet); } - catch (ArgumentException ex) + } + catch (FormatException ex) + { + if (!SkipHeaderValidation) + { + ErrorRecord er = new ErrorRecord(ex, "WebCmdletContentTypeException", ErrorCategory.InvalidArgument, ContentType); + ThrowTerminatingError(er); + } + } + catch (ArgumentException ex) + { + if (!SkipHeaderValidation) { ErrorRecord er = new ErrorRecord(ex, "WebCmdletEncodingException", ErrorCategory.InvalidArgument, ContentType); ThrowTerminatingError(er); From db019b30a99de046d90565500561cf19852bce03 Mon Sep 17 00:00:00 2001 From: Mark Kraus Date: Thu, 25 Jan 2018 04:07:41 -0600 Subject: [PATCH 2/5] Move -SkipHeaderValidation Tests to Contexts --- .../WebCmdlets.Tests.ps1 | 192 +++++++++--------- 1 file changed, 95 insertions(+), 97 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 05356b2edf8..da4366ec7bf 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -801,68 +801,68 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { #endregion Redirect tests - #region SkipHeaderVerification Tests + Context "Invoke-WebRequest SkipHeaderVerification Tests" { + It "Verifies Invoke-WebRequest default header handling with no errors" { + $uri = Get-WebListenerUrl -Test 'Get' + $headers = @{"If-Match" = "*"} + $response = ExecuteRequestWithCustomHeaders -Uri $uri -headers $headers - It "Verifies Invoke-WebRequest default header handling with no errors" { - $uri = Get-WebListenerUrl -Test 'Get' - $headers = @{"If-Match" = "*"} - $response = ExecuteRequestWithCustomHeaders -Uri $uri -headers $headers + $response.Error | Should BeNullOrEmpty + $response.Content.Headers."If-Match" | Should BeExactly "*" + } - $response.Error | Should BeNullOrEmpty - $response.Content.Headers."If-Match" | Should BeExactly "*" - } + It "Verifies Invoke-WebRequest default header handling reports an error is returned for an invalid If-Match header value" { + $uri = Get-WebListenerUrl -Test 'Get' + $headers = @{"If-Match" = "12345"} + $response = ExecuteRequestWithCustomHeaders -Uri $uri -headers $headers - It "Verifies Invoke-WebRequest default header handling reports an error is returned for an invalid If-Match header value" { - $uri = Get-WebListenerUrl -Test 'Get' - $headers = @{"If-Match" = "12345"} - $response = ExecuteRequestWithCustomHeaders -Uri $uri -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." + } - $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" { + $uri = Get-WebListenerUrl -Test 'Get' + $headers = @{"If-Match" = "12345"} + $response = ExecuteRequestWithCustomHeaders -Uri $uri -headers $headers -SkipHeaderValidation - It "Verifies Invoke-WebRequest header handling does not report an error when using -SkipHeaderValidation" { - $uri = Get-WebListenerUrl -Test 'Get' - $headers = @{"If-Match" = "12345"} - $response = ExecuteRequestWithCustomHeaders -Uri $uri -headers $headers -SkipHeaderValidation + $response.Error | Should BeNullOrEmpty + $response.Content.Headers."If-Match" | Should BeExactly "12345" + } - $response.Error | Should BeNullOrEmpty - $response.Content.Headers."If-Match" | Should BeExactly "12345" - } + It "Verifies Invoke-WebRequest default UserAgent handling with no errors" { + $uri = Get-WebListenerUrl -Test 'Get' + $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::InternetExplorer + $response = ExecuteRequestWithCustomUserAgent -Uri $uri -UserAgent $UserAgent -Cmdlet "Invoke-WebRequest" - It "Verifies Invoke-WebRequest default UserAgent handling with no errors" { - $uri = Get-WebListenerUrl -Test 'Get' - $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::InternetExplorer - $response = ExecuteRequestWithCustomUserAgent -Uri $uri -UserAgent $UserAgent -Cmdlet "Invoke-WebRequest" + $response.Error | Should BeNullOrEmpty + $Pattern = [regex]::Escape($UserAgent) + $response.Content.Headers."User-Agent" | Should Match $Pattern + } - $response.Error | Should BeNullOrEmpty - $Pattern = [regex]::Escape($UserAgent) - $response.Content.Headers."User-Agent" | Should Match $Pattern - } + It "Verifies Invoke-WebRequest default UserAgent handling reports an error is returned for an invalid UserAgent value" { + $uri = Get-WebListenerUrl -Test 'Get' + $UserAgent = 'Invalid:Agent' + $response = ExecuteRequestWithCustomUserAgent -Uri $uri -UserAgent $UserAgent -Cmdlet "Invoke-WebRequest" - It "Verifies Invoke-WebRequest default UserAgent handling reports an error is returned for an invalid UserAgent value" { - $uri = Get-WebListenerUrl -Test 'Get' - $UserAgent = 'Invalid:Agent' - $response = ExecuteRequestWithCustomUserAgent -Uri $uri -UserAgent $UserAgent -Cmdlet "Invoke-WebRequest" + $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 'Invalid:Agent' is invalid." + } - $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 'Invalid:Agent' is invalid." - } + It "Verifies Invoke-WebRequest UserAgent handling does not report an error when using -SkipHeaderValidation" { + $uri = Get-WebListenerUrl -Test 'Get' + $UserAgent = 'Invalid:Agent' + $response = ExecuteRequestWithCustomUserAgent -Uri $uri -UserAgent $UserAgent -SkipHeaderValidation -Cmdlet "Invoke-WebRequest" - It "Verifies Invoke-WebRequest UserAgent handling does not report an error when using -SkipHeaderValidation" { - $uri = Get-WebListenerUrl -Test 'Get' - $UserAgent = 'Invalid:Agent' - $response = ExecuteRequestWithCustomUserAgent -Uri $uri -UserAgent $UserAgent -SkipHeaderValidation -Cmdlet "Invoke-WebRequest" + $response.Error | Should BeNullOrEmpty + $Pattern = [regex]::Escape($UserAgent) + $response.Content.Headers."User-Agent" | Should Match $Pattern + } - $response.Error | Should BeNullOrEmpty - $Pattern = [regex]::Escape($UserAgent) - $response.Content.Headers."User-Agent" | Should Match $Pattern + It } - #endregion SkipHeaderVerification Tests - #region charset encoding tests Context "BasicHtmlWebResponseObject Encoding tests" { @@ -1922,68 +1922,66 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { #endregion Redirect tests - #region SkipHeaderVerification tests + Context "Invoke-RestMethod SkipHeaderVerification Tests" { + It "Verifies Invoke-RestMethod default header handling with no errors" { + $uri = Get-WebListenerUrl -Test 'Get' + $headers = @{"If-Match" = "*"} + $response = ExecuteRequestWithCustomHeaders -Uri $uri -headers $headers -Cmdlet "Invoke-RestMethod" - It "Verifies Invoke-RestMethod default header handling with no errors" { - $uri = Get-WebListenerUrl -Test 'Get' - $headers = @{"If-Match" = "*"} - $response = ExecuteRequestWithCustomHeaders -Uri $uri -headers $headers -Cmdlet "Invoke-RestMethod" - - $response.Error | Should BeNullOrEmpty - $response.Content.Headers."If-Match" | Should BeExactly "*" - } + $response.Error | Should BeNullOrEmpty + $response.Content.Headers."If-Match" | Should BeExactly "*" + } - It "Verifies Invoke-RestMethod default header handling reports an error is returned for an invalid If-Match header value" { - $uri = Get-WebListenerUrl -Test 'Get' - $headers = @{"If-Match" = "12345"} - $response = ExecuteRequestWithCustomHeaders -Uri $uri -headers $headers -Cmdlet "Invoke-RestMethod" + It "Verifies Invoke-RestMethod default header handling reports an error is returned for an invalid If-Match header value" { + $uri = Get-WebListenerUrl -Test 'Get' + $headers = @{"If-Match" = "12345"} + $response = ExecuteRequestWithCustomHeaders -Uri $uri -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." - } + $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" { - $uri = Get-WebListenerUrl -Test 'Get' - $headers = @{"If-Match" = "12345"} - $response = ExecuteRequestWithCustomHeaders -Uri $uri -headers $headers -SkipHeaderValidation -Cmdlet "Invoke-RestMethod" + It "Verifies Invoke-RestMethod header handling does not report an error when using -SkipHeaderValidation" { + $uri = Get-WebListenerUrl -Test 'Get' + $headers = @{"If-Match" = "12345"} + $response = ExecuteRequestWithCustomHeaders -Uri $uri -headers $headers -SkipHeaderValidation -Cmdlet "Invoke-RestMethod" - $response.Error | Should BeNullOrEmpty - $response.Content.Headers."If-Match" | Should BeExactly "12345" - } + $response.Error | Should BeNullOrEmpty + $response.Content.Headers."If-Match" | Should BeExactly "12345" + } - It "Verifies Invoke-RestMethod default UserAgent handling with no errors" { - $uri = Get-WebListenerUrl -Test 'Get' - $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::InternetExplorer - $response = ExecuteRequestWithCustomUserAgent -Uri $uri -UserAgent $UserAgent -Cmdlet "Invoke-RestMethod" + It "Verifies Invoke-RestMethod default UserAgent handling with no errors" { + $uri = Get-WebListenerUrl -Test 'Get' + $UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::InternetExplorer + $response = ExecuteRequestWithCustomUserAgent -Uri $uri -UserAgent $UserAgent -Cmdlet "Invoke-RestMethod" - $response.Error | Should BeNullOrEmpty - $Pattern = [regex]::Escape($UserAgent) - $response.Content.Headers."User-Agent" | Should Match $Pattern - } + $response.Error | Should BeNullOrEmpty + $Pattern = [regex]::Escape($UserAgent) + $response.Content.Headers."User-Agent" | Should Match $Pattern + } - It "Verifies Invoke-RestMethod default UserAgent handling reports an error is returned for an invalid UserAgent value" { - $uri = Get-WebListenerUrl -Test 'Get' - $UserAgent = 'Invalid:Agent' - $response = ExecuteRequestWithCustomUserAgent -Uri $uri -UserAgent $UserAgent -Cmdlet "Invoke-RestMethod" + It "Verifies Invoke-RestMethod default UserAgent handling reports an error is returned for an invalid UserAgent value" { + $uri = Get-WebListenerUrl -Test 'Get' + $UserAgent = 'Invalid:Agent' + $response = ExecuteRequestWithCustomUserAgent -Uri $uri -UserAgent $UserAgent -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 'Invalid:Agent' is invalid." - } + $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 'Invalid:Agent' is invalid." + } - It "Verifies Invoke-RestMethod UserAgent handling does not report an error when using -SkipHeaderValidation" { - $uri = Get-WebListenerUrl -Test 'Get' - $UserAgent = 'Invalid:Agent' - $response = ExecuteRequestWithCustomUserAgent -Uri $uri -UserAgent $UserAgent -SkipHeaderValidation -Cmdlet "Invoke-RestMethod" + It "Verifies Invoke-RestMethod UserAgent handling does not report an error when using -SkipHeaderValidation" { + $uri = Get-WebListenerUrl -Test 'Get' + $UserAgent = 'Invalid:Agent' + $response = ExecuteRequestWithCustomUserAgent -Uri $uri -UserAgent $UserAgent -SkipHeaderValidation -Cmdlet "Invoke-RestMethod" - $response.Error | Should BeNullOrEmpty - $Pattern = [regex]::Escape($UserAgent) - $response.Content.Headers."User-Agent" | Should Match $Pattern + $response.Error | Should BeNullOrEmpty + $Pattern = [regex]::Escape($UserAgent) + $response.Content.Headers."User-Agent" | Should Match $Pattern + } } - #endregion SkipHeaderVerification tests - Context "HTTPS Tests" { It "Validate Invoke-RestMethod -SkipCertificateCheck" { # HTTP method HEAD must be used to not retrieve an unparsable HTTP body From 42bc29bbcf32325da21b4b5a135608c807be8b12 Mon Sep 17 00:00:00 2001 From: Mark Kraus Date: Thu, 25 Jan 2018 04:43:45 -0600 Subject: [PATCH 3/5] [Feature] Add ContentType -SkipHeaderValidation Tests --- .../WebCmdlets.Tests.ps1 | 136 +++++++++++++++++- 1 file changed, 135 insertions(+), 1 deletion(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index da4366ec7bf..d6e53ef7c2e 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -802,6 +802,11 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { #endregion Redirect tests Context "Invoke-WebRequest SkipHeaderVerification Tests" { + BeforeAll { + $Testfile = Join-Path $testdrive 'SkipHeaderVerification.txt' + 'bar' | Set-Content $Testfile + } + It "Verifies Invoke-WebRequest default header handling with no errors" { $uri = Get-WebListenerUrl -Test 'Get' $headers = @{"If-Match" = "*"} @@ -860,7 +865,70 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { $response.Content.Headers."User-Agent" | Should Match $Pattern } - It + It "Verifies Invoke-WebRequest default ContentType handling reports no error is returned for a valid Content-Type header value and -Body" { + $contentType = 'text/plain' + $body = "bar" + $uri = Get-WebListenerUrl -Test 'Post' + + $response = Invoke-WebRequest -Uri $uri -Method 'Post' -ContentType $contentType -Body $body + $result = $response.Content | ConvertFrom-Json + + $result.data | Should BeExactly $body + $result.headers.'Content-Type' | Should BeExactly $contentType + } + + It "Verifies Invoke-WebRequest default ContentType handling reports an error is returned for an invalid Content-Type header value and -Body" { + $contentType = 'foo' + $body = "bar" + $uri = Get-WebListenerUrl -Test 'Post' + + { Invoke-WebRequest -Uri $uri -Method 'Post' -ContentType $contentType -Body $body -ErrorAction 'Stop' } | + ShouldBeErrorId "WebCmdletContentTypeException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand" + } + + It "Verifies Invoke-WebRequest ContentType handling reports no error is returned for an invalid Content-Type header value, -Body, and -SkipHeaderValidation" { + $contentType = 'foo' + $body = "bar" + $uri = Get-WebListenerUrl -Test 'Post' + + $response = Invoke-WebRequest -Uri $uri -Method 'Post' -ContentType $contentType -Body $body -SkipHeaderValidation + $result = $response.Content | ConvertFrom-Json + + $result.data | Should BeExactly 'bar' + $result.headers.'Content-Type' | Should BeExactly $contentType + } + + It "Verifies Invoke-WebRequest default ContentType handling reports no error is returned for a valid Content-Type header value and -InFile" { + $contentType = 'text/plain' + $uri = Get-WebListenerUrl -Test 'Post' + + $response = Invoke-WebRequest -Uri $uri -Method 'Post' -ContentType $contentType -InFile $Testfile + $result = $response.Content | ConvertFrom-Json + + # Match used due to inconsistent newline rendering + $result.data | Should Match 'bar' + $result.headers.'Content-Type' | Should BeExactly $contentType + } + + It "Verifies Invoke-WebRequest default ContentType handling reports an error is returned for an invalid Content-Type header value and -InFile" { + $contentType = 'foo' + $uri = Get-WebListenerUrl -Test 'Post' + + { Invoke-WebRequest -Uri $uri -Method 'Post' -ContentType $contentType -InFile $Testfile -ErrorAction 'Stop' } | + ShouldBeErrorId "System.FormatException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand" + } + + It "Verifies Invoke-WebRequest default ContentType handling reports no error is returned for an invalid Content-Type header value, -Infile, and -SkipHeaderValidation" { + $contentType = 'foo' + $uri = Get-WebListenerUrl -Test 'Post' + + $response = Invoke-WebRequest -Uri $uri -Method 'Post' -ContentType $contentType -InFile $Testfile -SkipHeaderValidation + $result = $response.Content | ConvertFrom-Json + + # Match used due to inconsistent newline rendering + $result.data | Should Match 'bar' + $result.headers.'Content-Type' | Should BeExactly $contentType + } } #region charset encoding tests @@ -1923,6 +1991,11 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { #endregion Redirect tests Context "Invoke-RestMethod SkipHeaderVerification Tests" { + BeforeAll { + $Testfile = Join-Path $testdrive 'SkipHeaderVerification.txt' + 'bar' | Set-Content $Testfile + } + It "Verifies Invoke-RestMethod default header handling with no errors" { $uri = Get-WebListenerUrl -Test 'Get' $headers = @{"If-Match" = "*"} @@ -1980,6 +2053,67 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { $Pattern = [regex]::Escape($UserAgent) $response.Content.Headers."User-Agent" | Should Match $Pattern } + + It "Verifies Invoke-RestMethod default ContentType handling reports no error is returned for a valid Content-Type header value and -Body" { + $contentType = 'text/plain' + $body = "bar" + $uri = Get-WebListenerUrl -Test 'Post' + + $result = Invoke-RestMethod -Uri $uri -Method 'Post' -ContentType $contentType -Body $body + + $result.data | Should BeExactly $body + $result.headers.'Content-Type' | Should BeExactly $contentType + } + + It "Verifies Invoke-RestMethod default ContentType handling reports an error is returned for an invalid Content-Type header value and -Body" { + $contentType = 'foo' + $body = "bar" + $uri = Get-WebListenerUrl -Test 'Post' + + { Invoke-RestMethod -Uri $uri -Method 'Post' -ContentType $contentType -Body $body -ErrorAction 'Stop' } | + ShouldBeErrorId "WebCmdletContentTypeException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand" + } + + It "Verifies Invoke-RestMethod ContentType handling reports no error is returned for an invalid Content-Type header value, -Body, and -SkipHeaderValidation" { + $contentType = 'foo' + $body = "bar" + $uri = Get-WebListenerUrl -Test 'Post' + + $result = Invoke-RestMethod -Uri $uri -Method 'Post' -ContentType $contentType -Body $body -SkipHeaderValidation + + $result.data | Should BeExactly $body + $result.headers.'Content-Type' | Should BeExactly $contentType + } + + It "Verifies Invoke-RestMethod default ContentType handling reports no error is returned for a valid Content-Type header value and -InFile" { + $contentType = 'text/plain' + $uri = Get-WebListenerUrl -Test 'Post' + + $result = Invoke-RestMethod -Uri $uri -Method 'Post' -ContentType $contentType -InFile $Testfile + + # Match used due to inconsistent newline rendering + $result.data | Should Match 'bar' + $result.headers.'Content-Type' | Should BeExactly $contentType + } + + It "Verifies Invoke-RestMethod default ContentType handling reports an error is returned for an invalid Content-Type header value and -InFile" { + $contentType = 'foo' + $uri = Get-WebListenerUrl -Test 'Post' + + { Invoke-RestMethod -Uri $uri -Method 'Post' -ContentType $contentType -InFile $Testfile -ErrorAction 'Stop' } | + ShouldBeErrorId "System.FormatException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand" + } + + It "Verifies Invoke-RestMethod default ContentType handling reports no error is returned for an invalid Content-Type header value, -Infile, and -SkipHeaderValidation" { + $contentType = 'foo' + $uri = Get-WebListenerUrl -Test 'Post' + + $result = Invoke-RestMethod -Uri $uri -Method 'Post' -ContentType $contentType -InFile $Testfile -SkipHeaderValidation + + # Match used due to inconsistent newline rendering + $result.data | Should Match 'bar' + $result.headers.'Content-Type' | Should BeExactly $contentType + } } Context "HTTPS Tests" { From b5f8245605b39864359577573b4748309525a3df Mon Sep 17 00:00:00 2001 From: Mark Kraus Date: Thu, 25 Jan 2018 14:21:38 -0600 Subject: [PATCH 4/5] [feature] Improve ContentType Exception --- .../WebCmdlet/Common/WebRequestPSCmdlet.Common.cs | 10 +++++++++- .../Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 | 4 ++-- 2 files changed, 11 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 1d6c8848d0a..ddc087e467a 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 @@ -1182,7 +1182,15 @@ internal virtual void FillRequestStream(HttpRequestMessage request) } else { - request.Content.Headers.Add(entry.Key, entry.Value); + try + { + request.Content.Headers.Add(entry.Key, entry.Value); + } + catch (FormatException ex) + { + ErrorRecord er = new ErrorRecord(ex, "WebCmdletContentTypeException", ErrorCategory.InvalidArgument, ContentType); + ThrowTerminatingError(er); + } } } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index d6e53ef7c2e..b5c10809fc1 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -915,7 +915,7 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { $uri = Get-WebListenerUrl -Test 'Post' { Invoke-WebRequest -Uri $uri -Method 'Post' -ContentType $contentType -InFile $Testfile -ErrorAction 'Stop' } | - ShouldBeErrorId "System.FormatException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand" + ShouldBeErrorId "WebCmdletContentTypeException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand" } It "Verifies Invoke-WebRequest default ContentType handling reports no error is returned for an invalid Content-Type header value, -Infile, and -SkipHeaderValidation" { @@ -2101,7 +2101,7 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { $uri = Get-WebListenerUrl -Test 'Post' { Invoke-RestMethod -Uri $uri -Method 'Post' -ContentType $contentType -InFile $Testfile -ErrorAction 'Stop' } | - ShouldBeErrorId "System.FormatException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand" + ShouldBeErrorId "WebCmdletContentTypeException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand" } It "Verifies Invoke-RestMethod default ContentType handling reports no error is returned for an invalid Content-Type header value, -Infile, and -SkipHeaderValidation" { From eb541749b92cb5eb9f8c9a1d1658bed2af05f015 Mon Sep 17 00:00:00 2001 From: Mark Kraus Date: Fri, 26 Jan 2018 05:08:49 -0600 Subject: [PATCH 5/5] [feature] Improve error message on invalid -ContentType --- .../WebCmdlet/Common/WebRequestPSCmdlet.Common.cs | 9 ++++++--- .../resources/WebCmdletStrings.resx | 3 +++ 2 files changed, 9 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 ddc087e467a..12806ac3e32 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 @@ -1188,7 +1188,8 @@ internal virtual void FillRequestStream(HttpRequestMessage request) } catch (FormatException ex) { - ErrorRecord er = new ErrorRecord(ex, "WebCmdletContentTypeException", ErrorCategory.InvalidArgument, ContentType); + var outerEx = new ValidationMetadataException(WebCmdletStrings.ContentTypeException, ex); + ErrorRecord er = new ErrorRecord(outerEx, "WebCmdletContentTypeException", ErrorCategory.InvalidArgument, ContentType); ThrowTerminatingError(er); } } @@ -1503,7 +1504,8 @@ internal long SetRequestContent(HttpRequestMessage request, string content) { if (!SkipHeaderValidation) { - ErrorRecord er = new ErrorRecord(ex, "WebCmdletContentTypeException", ErrorCategory.InvalidArgument, ContentType); + var outerEx = new ValidationMetadataException(WebCmdletStrings.ContentTypeException, ex); + ErrorRecord er = new ErrorRecord(outerEx, "WebCmdletContentTypeException", ErrorCategory.InvalidArgument, ContentType); ThrowTerminatingError(er); } } @@ -1511,7 +1513,8 @@ internal long SetRequestContent(HttpRequestMessage request, string content) { if (!SkipHeaderValidation) { - ErrorRecord er = new ErrorRecord(ex, "WebCmdletEncodingException", ErrorCategory.InvalidArgument, ContentType); + var outerEx = new ValidationMetadataException(WebCmdletStrings.ContentTypeException, ex); + ErrorRecord er = new ErrorRecord(outerEx, "WebCmdletContentTypeException", ErrorCategory.InvalidArgument, ContentType); ThrowTerminatingError(er); } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx index 0c50ddd38ca..82958bbe76a 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/WebCmdletStrings.resx @@ -144,6 +144,9 @@ The cmdlet cannot run because the following conflicting parameters are specified: InFile and Form. Specify either InFile or Form, then retry. + + The cmdlet cannot run because the -ContentType parameter is not a valid Content-Type header. Specify a valid Content-Type for -ContentType, then retry. To suppress header validation, supply the -SkipHeaderValidation parameter. + The cmdlet cannot run because the following conflicting parameters are specified: Credential and UseDefaultCredentials. Specify either Credential or UseDefaultCredentials, then retry.