From 95a8a642601bca3f3e87162f7c5f61d457beff0f Mon Sep 17 00:00:00 2001 From: Mark Kraus Date: Mon, 4 Dec 2017 11:52:14 -0600 Subject: [PATCH] Replace HttpListener Response Tests with WebListener (#5540) * Add Response Controller * [Feature] Replace HttpListener Response tests with WebListener --- .../WebCmdlets.Tests.ps1 | 528 ++++++------------ .../Modules/WebListener/WebListener.psm1 | 1 + test/tools/WebListener/Constants.cs | 6 + .../Controllers/ResponseController.cs | 103 ++++ test/tools/WebListener/README.md | 35 ++ .../tools/WebListener/Views/Home/Index.cshtml | 1 + 6 files changed, 328 insertions(+), 346 deletions(-) create mode 100644 test/tools/WebListener/Controllers/ResponseController.cs diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 656d0bec69..9cd0ae22d1 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -788,7 +788,8 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { It "Validate Invoke-WebRequest returns empty RelationLink property if there is no Link Header" { - $command = "Invoke-WebRequest -Uri http://localhost:8080/PowerShell?test=response" + $uri = $uri = Get-WebListenerUrl -Test 'Get' + $command = "Invoke-WebRequest -Uri '$uri'" $result = ExecuteWebCommand -command $command $result.Output.RelationLink.Count | Should Be 0 @@ -805,14 +806,18 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { # Test pending support for multiple header capable server on Linux/macOS see issue #4639 It "Validate Invoke-WebRequest returns valid RelationLink property with absolute uris if Multiple Link Headers are present" -Pending:$(!$IsWindows){ - $headers = @{ - Link = - '; rel="self"', - '; rel="next"', - '; rel="last"' - } | ConvertTo-Json -Compress - $headers = [uri]::EscapeDataString($headers) - $uri = "http://localhost:8080/PowerShell?test=response&contenttype=text/plain&output=OK&headers=$headers" + $Query = @{ + body = "ok" + contenttype = 'text/plain' + headers = @{ + Link = @( + '; rel="self"' + '; rel="next"' + '; rel="last"' + ) + } | ConvertTo-Json -Compress + } + $Uri = Get-WebListenerUrl -Test 'Response' -Query $Query $command = "Invoke-WebRequest -Uri '$uri'" $result = ExecuteWebCommand -command $command $result.Output.RelationLink.Count | Should BeExactly 3 @@ -946,9 +951,13 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { Context "BasicHtmlWebResponseObject Encoding tests" { It "Verifies Invoke-WebRequest detects charset meta value when the ContentType header does not define it." { - $output = '' + $query = @{ + contenttype = 'text/html' + body = '' + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query $expectedEncoding = [System.Text.Encoding]::GetEncoding('Unicode') - $response = ExecuteWebRequest -Uri "http://localhost:8080/PowerShell?test=response&output=$output" -UseBasicParsing + $response = ExecuteWebRequest -Uri $uri -UseBasicParsing $response.Error | Should BeNullOrEmpty $response.Output.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName @@ -956,17 +965,13 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { } It "Verifies Invoke-WebRequest detects charset meta value when newlines are encountered in the element." { - $output = @' - - - - - -'@ + $query = @{ + contenttype = 'text/html' + body = "`n `n `n `n" + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query $expectedEncoding = [System.Text.Encoding]::GetEncoding('Unicode') - $response = ExecuteWebRequest -Uri "http://localhost:8080/PowerShell?test=response&output=$output" -UseBasicParsing + $response = ExecuteWebRequest -Uri $uri -UseBasicParsing $response.Error | Should BeNullOrEmpty $response.Output.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName @@ -974,9 +979,13 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { } It "Verifies Invoke-WebRequest detects charset meta value when the attribute value is unquoted." { - $output = '' + $query = @{ + contenttype = 'text/html' + body = '' + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query $expectedEncoding = [System.Text.Encoding]::GetEncoding('Unicode') - $response = ExecuteWebRequest -Uri "http://localhost:8080/PowerShell?test=response&output=$output" -UseBasicParsing + $response = ExecuteWebRequest -Uri $uri -UseBasicParsing $response.Error | Should BeNullOrEmpty $response.Output.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName @@ -984,14 +993,13 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { } It "Verifies Invoke-WebRequest detects http-equiv charset meta value when the ContentType header does not define it." { - $output = @' - - - - -'@ + $query = @{ + contenttype = 'text/html' + body = "`n`n`n" + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query $expectedEncoding = [System.Text.Encoding]::GetEncoding('Unicode') - $response = ExecuteWebRequest -Uri "http://localhost:8080/PowerShell?test=response&output=$output" -UseBasicParsing + $response = ExecuteWebRequest -Uri $uri -UseBasicParsing $response.Error | Should BeNullOrEmpty $response.Output.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName @@ -999,16 +1007,13 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { } It "Verifies Invoke-WebRequest detects http-equiv charset meta value newlines are encountered in the element." { - $output = @' - - - - -'@ + $query = @{ + contenttype = 'text/html' + body = "`n`n`n" + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query $expectedEncoding = [System.Text.Encoding]::GetEncoding('Unicode') - $response = ExecuteWebRequest -Uri "http://localhost:8080/PowerShell?test=response&output=$output" -UseBasicParsing + $response = ExecuteWebRequest -Uri $uri -UseBasicParsing $response.Error | Should BeNullOrEmpty $response.Output.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName @@ -1016,10 +1021,14 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { } It "Verifies Invoke-WebRequest ignores meta charset value when Content-Type header defines it." { - $output = '' + $query = @{ + contenttype = 'text/html; charset=utf-8' + body = '' + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query # NOTE: meta charset should be ignored $expectedEncoding = [System.Text.Encoding]::UTF8 - $response = ExecuteWebRequest -Uri "http://localhost:8080/PowerShell?test=response&contenttype=text/html; charset=utf-8&output=$output" -UseBasicParsing + $response = ExecuteWebRequest -Uri $uri -UseBasicParsing $response.Error | Should BeNullOrEmpty $response.Output.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName @@ -1027,10 +1036,14 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { } It "Verifies Invoke-WebRequest honors non-utf8 charsets in the Content-Type header" { - $output = '' + $query = @{ + contenttype = 'text/html; charset=utf-16' + body = '' + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query # NOTE: meta charset should be ignored $expectedEncoding = [System.Text.Encoding]::GetEncoding('utf-16') - $response = ExecuteWebRequest -Uri "http://localhost:8080/PowerShell?test=response&contenttype=text/html; charset=utf-16&output=$output" -UseBasicParsing + $response = ExecuteWebRequest -Uri $uri -UseBasicParsing $response.Error | Should BeNullOrEmpty $response.Output.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName @@ -1038,9 +1051,13 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { } It "Verifies Invoke-WebRequest defaults to iso-8859-1 when an unsupported/invalid charset is declared" { - $output = '' + $query = @{ + contenttype = 'text/html' + body = '' + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query $expectedEncoding = [System.Text.Encoding]::GetEncoding('iso-8859-1') - $response = ExecuteWebRequest -Uri "http://localhost:8080/PowerShell?test=response&contenttype=text/html&output=$output" -UseBasicParsing + $response = ExecuteWebRequest -Uri $uri -UseBasicParsing $response.Error | Should BeNullOrEmpty $response.Output.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName @@ -1048,14 +1065,13 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { } It "Verifies Invoke-WebRequest defaults to iso-8859-1 when an unsupported/invalid charset is declared using http-equiv" { - $output = @' - - - - -'@ + $query = @{ + contenttype = 'text/html' + body = "`n`n`n" + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query $expectedEncoding = [System.Text.Encoding]::GetEncoding('iso-8859-1') - $response = ExecuteWebRequest -Uri "http://localhost:8080/PowerShell?test=response&contenttype=text/html&output=$output" -UseBasicParsing + $response = ExecuteWebRequest -Uri $uri -UseBasicParsing $response.Error | Should BeNullOrEmpty $response.Output.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName @@ -1063,127 +1079,16 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { } } - Context "HtmlWebResponseObject Encoding" { - # these tests are dependent on https://github.com/PowerShell/PowerShell/issues/2867 - # Currently, all paths return BasicHtmlWebResponseObject - It "Verifies Invoke-WebRequest detects charset meta value when the ContentType header does not define it." -Pending { - $output = '' - $expectedEncoding = [System.Text.Encoding]::GetEncoding('Unicode') - $response = ExecuteWebRequest -Uri "http://localhost:8080/PowerShell?test=response&output=$output" - - $response.Error | Should BeNullOrEmpty - $response.Output.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName - # Update to test for HtmlWebResponseObject when mshtl dependency has been resolved. - $response.Output | Should BeOfType 'Microsoft.PowerShell.Commands.HtmlWebResponseObject' - } - - It "Verifies Invoke-WebRequest detects charset meta value when newlines are encountered in the element." -Pending { - $output = @' - - - - - -'@ - $expectedEncoding = [System.Text.Encoding]::GetEncoding('Unicode') - $response = ExecuteWebRequest -Uri "http://localhost:8080/PowerShell?test=response&output=$output" - - $response.Error | Should BeNullOrEmpty - $response.Output.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName - $response.Output | Should BeOfType 'Microsoft.PowerShell.Commands.HtmlWebResponseObject' - } - - It "Verifies Invoke-WebRequest ignores meta charset value when Content-Type header defines it." -Pending { - $output = '' - # NOTE: meta charset should be ignored - $expectedEncoding = [System.Text.Encoding]::UTF8 - # Update to test for HtmlWebResponseObject when mshtl dependency has been resolved. - $response = ExecuteWebRequest -Uri "http://localhost:8080/PowerShell?test=response&contenttype=text/html; charset=utf-8&output=$output" - - $response.Error | Should BeNullOrEmpty - $response.Output.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName - # Update to test for HtmlWebResponseObject when mshtl dependency has been resolved. - $response.Output | Should BeOfType 'Microsoft.PowerShell.Commands.HtmlWebResponseObject' - } - - It "Verifies Invoke-WebRequest detects http-equiv charset meta value when the ContentType header does not define it." -Pending { - $output = @' - - - - -'@ - $expectedEncoding = [System.Text.Encoding]::GetEncoding('Unicode') - $response = ExecuteWebRequest -Uri "http://localhost:8080/PowerShell?test=response&output=$output" - - $response.Error | Should BeNullOrEmpty - $response.Output.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName - $response.Output | Should BeOfType 'Microsoft.PowerShell.Commands.HtmlWebResponseObject' - } - - It "Verifies Invoke-WebRequest detects http-equiv charset meta value newlines are encountered in the element." -Pending { - $output = @' - - - - -'@ - $expectedEncoding = [System.Text.Encoding]::GetEncoding('Unicode') - $response = ExecuteWebRequest -Uri "http://localhost:8080/PowerShell?test=response&output=$output" - - $response.Error | Should BeNullOrEmpty - $response.Output.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName - $response.Output | Should BeOfType 'Microsoft.PowerShell.Commands.HtmlWebResponseObject' - } - - It "Verifies Invoke-WebRequest honors non-utf8 charsets in the Content-Type header" -Pending { - $output = '' - # NOTE: meta charset should be ignored - $expectedEncoding = [System.Text.Encoding]::GetEncoding('utf-16') - $response = ExecuteWebRequest -Uri "http://localhost:8080/PowerShell?test=response&contenttype=text/html; charset=utf-16&output=$output" - - $response.Error | Should BeNullOrEmpty - $response.Output.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName - # Update to test for HtmlWebResponseObject when mshtl dependency has been resolved. - $response.Output | Should BeOfType 'Microsoft.PowerShell.Commands.HtmlWebResponseObject' - } - - It "Verifies Invoke-WebRequest defaults to iso-8859-1 when an unsupported/invalid charset is declared" -Pending { - $output = '' - $expectedEncoding = [System.Text.Encoding]::GetEncoding('iso-8859-1') - $response = ExecuteWebRequest -Uri "http://localhost:8080/PowerShell?test=response&contenttype=text/html&output=$output" - - $response.Error | Should BeNullOrEmpty - $response.Output.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName - # Update to test for HtmlWebResponseObject when mshtl dependency has been resolved. - $response.Output | Should BeOfType 'Microsoft.PowerShell.Commands.HtmlWebResponseObject' - } - - It "Verifies Invoke-WebRequest defaults to iso-8859-1 when an unsupported/invalid charset is declared using http-equiv" -Pending { - $output = @' - - - - -'@ - $expectedEncoding = [System.Text.Encoding]::GetEncoding('iso-8859-1') - $response = ExecuteWebRequest -Uri "http://localhost:8080/PowerShell?test=response&contenttype=text/html&output=$output" - - $response.Error | Should BeNullOrEmpty - $response.Output.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName - $response.Output | Should BeOfType 'Microsoft.PowerShell.Commands.HtmlWebResponseObject' - } - } - #endregion charset encoding tests #region Content Header Inclusion + It "Verifies Invoke-WebRequest includes Content headers in Headers property" { - $uri = "http://localhost:8080/PowerShell?test=response&contenttype=text/plain&output=OK" + $query = @{ + contenttype = 'text/plain' + body ='OK' + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query $command = "Invoke-WebRequest -Uri '$uri'" $result = ExecuteWebCommand -command $command ValidateResponse $result @@ -1193,7 +1098,11 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { } It "Verifies Invoke-WebRequest includes Content headers in RawContent property" { - $uri = "http://localhost:8080/PowerShell?test=response&contenttype=text/plain&output=OK" + $query = @{ + contenttype = 'text/plain' + body ='OK' + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query $command = "Invoke-WebRequest -Uri '$uri'" $result = ExecuteWebCommand -command $command ValidateResponse $result @@ -1202,13 +1111,17 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { $result.Output.RawContent | Should Match ([regex]::Escape('Content-Length: 2')) } - # Test pending due to HttpListener limitation on Linux/macOS + # Test pending due to limitation on Linux/macOS # https://github.com/PowerShell/PowerShell/pull/4640 - It "Verifies Invoke-WebRequest Supports Multiple response headers with same name" -Pending { - $headers = @{ - 'X-Fake-Header' = 'testvalue01','testvalue02' - } | ConvertTo-Json -Compress - $uri = "http://localhost:8080/PowerShell?test=response&contenttype=text/plain&output=OK&headers=$headers" + It "Verifies Invoke-WebRequest Supports Multiple response headers with same name" -Pending:$(!$IsWindows) { + $query = @{ + contenttype = 'text/plain' + body ='OK' + headers = @{ + 'X-Fake-Header' = @('testvalue01','testvalue02') + } | ConvertTo-Json -Compress + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query $command = "Invoke-WebRequest -Uri '$uri'" $result = ExecuteWebCommand -command $command ValidateResponse $result @@ -1500,7 +1413,7 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { @{SslProtocol = 'Tls11'; ActualProtocol = 'Tls11'} @{SslProtocol = 'Tls12'; ActualProtocol = 'Tls12'} # macOS does not support multiple SslProtocols - if (-not $IsMacOS) + if (-not $IsMacOS) { @{SslProtocol = 'Tls, Tls11, Tls12'; ActualProtocol = 'Tls12'} @{SslProtocol = 'Tls11, Tls12'; ActualProtocol = 'Tls12'} @@ -1514,7 +1427,7 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { # macOS does not support multiple SslProtocols and possible CoreFX for this combo on Linux if($IsWindows) { - + @{SslProtocol = 'Tls, Tls12'; ActualProtocol = 'Tls12'} } ) { @@ -1538,7 +1451,7 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { @{IntendedProtocol = 'Tls12'; ActualProtocol = 'Tls'} @{IntendedProtocol = 'Tls12'; ActualProtocol = 'Tls11'} # macOS does not support multiple SslProtocols - if (-not $IsMacOS) + if (-not $IsMacOS) { @{IntendedProtocol = 'Tls11, Tls12'; ActualProtocol = 'Tls'} @{IntendedProtocol = 'Tls, Tls12'; ActualProtocol = 'Tls11'} @@ -1909,7 +1822,12 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { It "Validate Invoke-RestMethod -FollowRelLink doesn't fail if no Link Header is present" { - $command = "Invoke-RestMethod -Uri 'http://localhost:8081/PowerShell?test=response&output=foo' -FollowRelLink" + $query = @{ + contenttype = 'application/json' + body = '"foo"' + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query + $command = "Invoke-RestMethod -Uri '$uri' -FollowRelLink" $result = ExecuteWebCommand -command $command $result.Output | Should BeExactly "foo" @@ -2135,212 +2053,119 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { Context "Invoke-RestMethod Encoding tests with BasicHtmlWebResponseObject response" { It "Verifies Invoke-RestMethod detects charset meta value when the ContentType header does not define it." { - $output = '' + $query = @{ + contenttype = 'text/html' + body = '' + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query $expectedEncoding = [System.Text.Encoding]::GetEncoding('Unicode') - $response = ExecuteRestMethod -Uri "http://localhost:8081/PowerShell?test=response&output=$output" -UseBasicParsing + $response = ExecuteRestMethod -Uri $uri -UseBasicParsing $response.Error | Should BeNullOrEmpty $response.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName } It "Verifies Invoke-WebRequest detects charset meta value when newlines are encountered in the element." { - $output = @' - - - - - -'@ + $query = @{ + contenttype = 'text/html' + body = "`n `n `n `n" + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query $expectedEncoding = [System.Text.Encoding]::GetEncoding('Unicode') - $response = ExecuteRestMethod -Uri "http://localhost:8081/PowerShell?test=response&output=$output" -UseBasicParsing + $response = ExecuteRestMethod -Uri $uri -UseBasicParsing $response.Error | Should BeNullOrEmpty $response.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName } It "Verifies Invoke-RestMethod detects charset meta value when the attribute value is unquoted." { - $output = '' + $query = @{ + contenttype = 'text/html' + body = '' + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query $expectedEncoding = [System.Text.Encoding]::GetEncoding('Unicode') - $response = ExecuteRestMethod -Uri "http://localhost:8081/PowerShell?test=response&output=$output" -UseBasicParsing + $response = ExecuteRestMethod -Uri $uri -UseBasicParsing $response.Error | Should BeNullOrEmpty $response.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName } It "Verifies Invoke-RestMethod detects http-equiv charset meta value when the ContentType header does not define it." { - $output = @' - - - - -'@ + $query = @{ + contenttype = 'text/html' + body = "`n`n`n" + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query $expectedEncoding = [System.Text.Encoding]::GetEncoding('Unicode') - $response = ExecuteRestMethod -Uri "http://localhost:8081/PowerShell?test=response&output=$output" -UseBasicParsing + $response = ExecuteRestMethod -Uri $uri -UseBasicParsing $response.Error | Should BeNullOrEmpty $response.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName } It "Verifies Invoke-RestMethod detects http-equiv charset meta value newlines are encountered in the element." { - $output = @' - - - - -'@ + $query = @{ + contenttype = 'text/html' + body = "`n`n`n`n" + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query $expectedEncoding = [System.Text.Encoding]::GetEncoding('Unicode') - $response = ExecuteRestMethod -Uri "http://localhost:8081/PowerShell?test=response&output=$output" -UseBasicParsing + $response = ExecuteRestMethod -Uri $uri -UseBasicParsing $response.Error | Should BeNullOrEmpty $response.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName } It "Verifies Invoke-RestMethod ignores meta charset value when Content-Type header defines it." { - $output = '' + $query = @{ + contenttype = 'text/html; charset=utf-8' + body = '' + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query # NOTE: meta charset should be ignored $expectedEncoding = [System.Text.Encoding]::UTF8 - $response = ExecuteRestMethod -Uri "http://localhost:8081/PowerShell?test=response&contenttype=text/html; charset=utf-8&output=$output" -UseBasicParsing + $response = ExecuteRestMethod -Uri $uri -UseBasicParsing $response.Error | Should BeNullOrEmpty $response.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName } It "Verifies Invoke-RestMethod honors non-utf8 charsets in the Content-Type header" { - $output = '' + $query = @{ + contenttype = 'text/html; charset=utf-16' + body = '' + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query # NOTE: meta charset should be ignored $expectedEncoding = [System.Text.Encoding]::GetEncoding('utf-16') - $response = ExecuteRestMethod -Uri "http://localhost:8081/PowerShell?test=response&contenttype=text/html; charset=utf-16&output=$output" -UseBasicParsing + $response = ExecuteRestMethod -Uri $uri -UseBasicParsing $response.Error | Should BeNullOrEmpty $response.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName } It "Verifies Invoke-RestMethod defaults to iso-8859-1 when an unsupported/invalid charset is declared" { - $output = '' + $query = @{ + contenttype = 'text/html' + body = '' + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query $expectedEncoding = [System.Text.Encoding]::GetEncoding('iso-8859-1') - $response = ExecuteRestMethod -Uri "http://localhost:8081/PowerShell?test=response&contenttype=text/html&output=$output" -UseBasicParsing + $response = ExecuteRestMethod -Uri $uri -UseBasicParsing $response.Error | Should BeNullOrEmpty $response.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName } It "Verifies Invoke-RestMethod defaults to iso-8859-1 when an unsupported/invalid charset is declared using http-equiv" { - $output = @' - - - - -'@ + $query = @{ + contenttype = 'text/html' + body = "`n`n`n" + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query $expectedEncoding = [System.Text.Encoding]::GetEncoding('iso-8859-1') - $response = ExecuteRestMethod -Uri "http://localhost:8081/PowerShell?test=response&contenttype=text/html&output=$output" -UseBasicParsing - - $response.Error | Should BeNullOrEmpty - $response.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName - } - } - - Context "Invoke-RestMethod Encoding tests with HtmlWebResponseObject response" { - # these tests are dependent on https://github.com/PowerShell/PowerShell/issues/2867 - # Currently, all paths return BasicHtmlWebResponseObject - It "Verifies Invoke-RestMethod detects charset meta value when the ContentType header does not define it." -Pending { - $output = '' - $expectedEncoding = [System.Text.Encoding]::GetEncoding('Unicode') - $response = ExecuteRestMethod -Uri "http://localhost:8081/PowerShell?test=response&output=$output" - - $response.Error | Should BeNullOrEmpty - $response.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName - } - - It "Verifies Invoke-RestMethod detects charset meta value when newlines are encountered in the element." -Pending { - $output = @' - - - - - -'@ - $expectedEncoding = [System.Text.Encoding]::GetEncoding('Unicode') - $response = ExecuteRestMethod -Uri "http://localhost:8081/PowerShell?test=response&output=$output" - - $response.Error | Should BeNullOrEmpty - $response.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName - } - - It "Verifies Invoke-RestMethod ignores meta charset value when Content-Type header defines it." -Pending { - $output = '' - # NOTE: meta charset should be ignored - $expectedEncoding = [System.Text.Encoding]::UTF8 - # Update to test for HtmlWebResponseObject when mshtl dependency has been resolved. - $response = ExecuteRestMethod -Uri "http://localhost:8081/PowerShell?test=response&contenttype=text/html; charset=utf-8&output=$output" - - $response.Error | Should BeNullOrEmpty - $response.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName - } - - It "Verifies Invoke-RestMethod detects http-equiv charset meta value when the ContentType header does not define it." -Pending { - $output = @' - - - - -'@ - $expectedEncoding = [System.Text.Encoding]::GetEncoding('Unicode') - $response = ExecuteRestMethod -Uri "http://localhost:8081/PowerShell?test=response&output=$output" - - $response.Error | Should BeNullOrEmpty - $response.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName - } - - It "Verifies Invoke-RestMethod detects http-equiv charset meta value newlines are encountered in the element." -Pending { - $output = @' - - - - -'@ - $expectedEncoding = [System.Text.Encoding]::GetEncoding('Unicode') - $response = ExecuteRestMethod -Uri "http://localhost:8081/PowerShell?test=response&output=$output" - - $response.Error | Should BeNullOrEmpty - $response.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName - } - - It "Verifies Invoke-RestMethod honors non-utf8 charsets in the Content-Type header" -Pending { - $output = '' - # NOTE: meta charset should be ignored - $expectedEncoding = [System.Text.Encoding]::GetEncoding('utf-16') - $response = ExecuteRestMethod -Uri "http://localhost:8081/PowerShell?test=response&contenttype=text/html; charset=utf-16&output=$output" - - $response.Error | Should BeNullOrEmpty - $response.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName - } - - It "Verifies Invoke-RestMethod defaults to iso-8859-1 when an unsupported/invalid charset is declared" -Pending { - $output = '' - $expectedEncoding = [System.Text.Encoding]::GetEncoding('iso-8859-1') - $response = ExecuteRestMethod -Uri "http://localhost:8081/PowerShell?test=response&contenttype=text/html&output=$output" - - $response.Error | Should BeNullOrEmpty - $response.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName - } - - It "Verifies Invoke-RestMethod defaults to iso-8859-1 when an unsupported/invalid charset is declared using http-equiv" -Pending { - $output = @' - - - - -'@ - $expectedEncoding = [System.Text.Encoding]::GetEncoding('iso-8859-1') - $response = ExecuteRestMethod -Uri "http://localhost:8081/PowerShell?test=response&contenttype=text/html&output=$output" + $response = ExecuteRestMethod -Uri $uri -UseBasicParsing $response.Error | Should BeNullOrEmpty $response.Encoding.EncodingName | Should Be $expectedEncoding.EncodingName @@ -2557,7 +2382,7 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { @{SslProtocol = 'Tls11'; ActualProtocol = 'Tls11'} @{SslProtocol = 'Tls12'; ActualProtocol = 'Tls12'} # macOS does not support multiple SslProtocols - if (-not $IsMacOS) + if (-not $IsMacOS) { @{SslProtocol = 'Tls, Tls11, Tls12'; ActualProtocol = 'Tls12'} @{SslProtocol = 'Tls11, Tls12'; ActualProtocol = 'Tls12'} @@ -2593,7 +2418,7 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { @{IntendedProtocol = 'Tls12'; ActualProtocol = 'Tls'} @{IntendedProtocol = 'Tls12'; ActualProtocol = 'Tls11'} # macOS does not support multiple SslProtocols - if (-not $IsMacOS) + if (-not $IsMacOS) { @{IntendedProtocol = 'Tls11, Tls12'; ActualProtocol = 'Tls'} @{IntendedProtocol = 'Tls, Tls12'; ActualProtocol = 'Tls11'} @@ -2614,18 +2439,24 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { } Context "Invoke-RestMethod Single Value JSON null support" { - BeforeAll { - $baseUrl = 'http://localhost:8081/PowerShell?test=response&contenttype=application/json&output=' - } It "Invoke-RestMethod Supports a Single Value JSON null" { - $url = '{0}{1}' -f $baseUrl, 'null' - Invoke-RestMethod -Uri $url | Should Be $null + $query = @{ + contenttype = 'application/json' + body = 'null' + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query + Invoke-RestMethod -Uri $uri | Should Be $null } It "Invoke-RestMethod Supports a Single Value JSON null and ignores whitespace" { - $url = '{0}{1}' -f $baseUrl, " null " - Invoke-RestMethod -Uri $url | Should Be $null - $url = '{0}{1}' -f $baseUrl, " null `n" - Invoke-RestMethod -Uri $url | Should Be $null + $query = @{ + contenttype = 'application/json' + body = " null " + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query + Invoke-RestMethod -Uri $uri | Should Be $null + $query['body'] = " null `n" + $uri = Get-WebListenerUrl -Test 'Response' -Query $query + Invoke-RestMethod -Uri $uri | Should Be $null } } @@ -2740,22 +2571,27 @@ Describe "Validate Invoke-WebRequest and Invoke-RestMethod -InFile" -Tags "Featu Describe "Web cmdlets tests using the cmdlet's aliases" -Tags "CI" { BeforeAll { - $response = Start-HttpListener -Port 8079 - } - - AfterAll { - $null = Stop-HttpListener -Port 8079 - $response.PowerShell.Dispose() + $WebListener = Start-WebListener } It "Execute Invoke-WebRequest" { - $result = iwr "http://localhost:8079/PowerShell?test=response&output=hello" -TimeoutSec 5 + $query = @{ + body = "hello" + contenttype = 'text/plain' + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query + $result = iwr $uri -TimeoutSec 5 $result.StatusCode | Should Be "200" $result.Content | Should Be "hello" } It "Execute Invoke-RestMethod" { - $result = irm "http://localhost:8079/PowerShell?test=response&output={%22hello%22:%22world%22}&contenttype=application/json" -TimeoutSec 5 + $query = @{ + contenttype = 'application/json' + body = @{Hello = "world"} | ConvertTo-Json -Compress + } + $uri = Get-WebListenerUrl -Test 'Response' -Query $query + $result = irm $uri -TimeoutSec 5 $result.Hello | Should Be "world" } } diff --git a/test/tools/Modules/WebListener/WebListener.psm1 b/test/tools/Modules/WebListener/WebListener.psm1 index 9c51a9b171..981f09f2bb 100644 --- a/test/tools/Modules/WebListener/WebListener.psm1 +++ b/test/tools/Modules/WebListener/WebListener.psm1 @@ -136,6 +136,7 @@ function Get-WebListenerUrl { 'Home', 'Multipart', 'Redirect', + 'Response', 'ResponseHeaders', '/' )] diff --git a/test/tools/WebListener/Constants.cs b/test/tools/WebListener/Constants.cs index 1eae8c284f..b36a4e8081 100644 --- a/test/tools/WebListener/Constants.cs +++ b/test/tools/WebListener/Constants.cs @@ -5,5 +5,11 @@ namespace mvc.Controllers internal static class Constants { public const string HeaderSeparator = ", "; + public const string ApplicationJson = "application/json"; + } + + internal static class StatusCodes + { + public const Int32 ApplicationError = 500; } } diff --git a/test/tools/WebListener/Controllers/ResponseController.cs b/test/tools/WebListener/Controllers/ResponseController.cs new file mode 100644 index 0000000000..c2688cf055 --- /dev/null +++ b/test/tools/WebListener/Controllers/ResponseController.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.Extensions.Primitives; +using mvc.Models; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace mvc.Controllers +{ + public class ResponseController : Controller + { + public String Index() + { + string output = String.Empty; + string contentType = Constants.ApplicationJson; + + StringValues contentTypes; + if (Request.Query.TryGetValue("contenttype", out contentTypes)) + { + contentType = contentTypes.FirstOrDefault(); + } + + StringValues statusCodes; + Int32 statusCode; + if (Request.Query.TryGetValue("statuscode", out statusCodes) && + Int32.TryParse(statusCodes.FirstOrDefault(), out statusCode)) + { + Response.StatusCode = statusCode; + } + + StringValues body; + if (Request.Query.TryGetValue("body", out body)) + { + output = body.FirstOrDefault(); + } + + StringValues headers; + if (Request.Query.TryGetValue("headers", out headers)) + { + try + { + Response.Headers.Clear(); + JObject jobject = JObject.Parse(headers.FirstOrDefault()); + foreach (JProperty property in (JToken)jobject) + { + // Only set Content-Type through contenttype field. + if (String.Equals(property.Name, "Content-Type", StringComparison.InvariantCultureIgnoreCase)) + { + continue; + } + foreach (string entry in GetSingleOrArray(property.Value)) + { + Response.Headers.Append(property.Name,entry); + } + } + } + catch (Exception ex) + { + output = JsonConvert.SerializeObject(ex); + Response.StatusCode = StatusCodes.ApplicationError; + contentType = Constants.ApplicationJson; + } + } + + // Content-Type must be applied right before it is sent to the client or MVC will overwrite. + Response.OnStarting(state => + { + var httpContext = (HttpContext) state; + httpContext.Response.ContentType = contentType; + return Task.FromResult(0); + }, HttpContext); + + Response.ContentLength = Encoding.UTF8.GetBytes(output).Length; + + return output; + } + + public IActionResult Error() + { + return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); + } + + private List GetSingleOrArray(JToken token) + { + if (token.HasValues) + { + return token.ToObject>(); + } + else + { + return new List { token.ToObject() }; + } + } + } +} diff --git a/test/tools/WebListener/README.md b/test/tools/WebListener/README.md index a5ce45df0a..efa200a3e6 100644 --- a/test/tools/WebListener/README.md +++ b/test/tools/WebListener/README.md @@ -342,6 +342,41 @@ Location: /Get/

You should be redirected automatically to target URL: /Get/. If not click the link. ``` +## /Response/ + +Will return a response crafted from the query string. The following four fields are supported: + +* `body` - a string containing the response body +* `statuscode` - the HTTP Status Code to return +* `contenttype` - The `Content-Type` response header +* `headers` - a JSON string containing response headers. `Content-Type` will be ignored in `headers`. Use `contenttype` instead. + +```powershell +$Query = @{ + statsucode = 200 + contenttype = 'application/json' + body = '{"key1": "value1"}' + headers = @{ + "X-Header" = "Response header value" + } | ConvertTo-Json +} +$Uri = Get-WebListenerUrl -Test 'Response' -Query $Query +Invoke-RestMethod -Uri $uri +``` + +Response headers: + +```none +Content-Type: application/json +X-Header: Response header value +``` + +Response Body: + +```json +{"key1": "value1"} +``` + ## /ResponseHeaders/ Will return the response headers passed in query string. The response body will be the supplied headers as a JSON object. diff --git a/test/tools/WebListener/Views/Home/Index.cshtml b/test/tools/WebListener/Views/Home/Index.cshtml index 13699a36b3..253ed6879e 100644 --- a/test/tools/WebListener/Views/Home/Index.cshtml +++ b/test/tools/WebListener/Views/Home/Index.cshtml @@ -12,5 +12,6 @@

  • /Get/ - Emulates functionality of https://httpbin.org/get by returning GET headers, Arguments, and Request URL
  • /Multipart/ - Multipart/form-data submission testing
  • /Redirect/{count} - 302 redirect count times.
  • +
  • /Response/?statuscode=<StatusCode>&body=<ResponseBody>&contenttype=<ResponseContentType>&headers=<JsonHeadersObject> - Returns the given response.
  • /ResponseHeaders/?key=val - Returns given response headers.