From 28e42d650765bd3b6a3dd0130e0b2d036d351d83 Mon Sep 17 00:00:00 2001 From: markekraus Date: Fri, 29 Sep 2017 05:10:01 -0500 Subject: [PATCH 1/7] Add Gzip and Deflate Support to WebListener --- .../WebCmdlets.Tests.ps1 | 66 +++++++------------ .../Modules/WebListener/WebListener.psm1 | 1 + .../Controllers/CompressionController.cs | 42 ++++++++++++ test/tools/WebListener/DeflateFilter.cs | 30 +++++++++ test/tools/WebListener/GzipFilter.cs | 30 +++++++++ test/tools/WebListener/README.md | 40 +++++++++++ 6 files changed, 168 insertions(+), 41 deletions(-) create mode 100644 test/tools/WebListener/Controllers/CompressionController.cs create mode 100644 test/tools/WebListener/DeflateFilter.cs create mode 100644 test/tools/WebListener/GzipFilter.cs diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 86e239cfdfe..2f283101045 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -592,29 +592,22 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { # gzip Returns gzip-encoded data. # deflate Returns deflate-encoded data. # $dataEncodings = @("Chunked", "Compress", "Deflate", "GZip", "Identity") - # Note: These are the supported options, but we do not have a web service to test them all. - # $dataEncodings = @("gzip", "deflate") --> Currently there is a bug for deflate encoding. Please see '7976639:Invoke-WebRequest does not support -TransferEncoding deflate' for more info. - $dataEncodings = @("gzip") - foreach ($data in $dataEncodings) - { - It "Invoke-WebRequest supports request that returns $data-encoded data." { - - $command = "Invoke-WebRequest -Uri http://httpbin.org/$data -TimeoutSec 5" + # Note: These are the supported options, but we do not have a web service to test them all. + It "Invoke-WebRequest supports request that returns -encoded data." -TestCases @( + @{ DataEncoding = "gzip"} + @{ DataEncoding = "deflate"} + ) { + param($dataEncoding) + $uri = Get-WebListenerUrl -Test 'Compression' -TestValue $dataEncoding + $command = "Invoke-WebRequest -Uri '$uri'" - $result = ExecuteWebCommand -command $command - ValidateResponse -response $result + $result = ExecuteWebCommand -command $command + ValidateResponse -response $result - # Validate response content - $jsonContent = $result.Output.Content | ConvertFrom-Json - if ($data -eq "gzip") - { - $jsonContent.gzipped | Should Match $true - } - else - { - $jsonContent.deflated | Should Match $true - } - } + # Validate response content + $result.Output.Headers.'Content-Encoding'[0] | Should Be $dataEncoding + $jsonContent = $result.Output.Content | ConvertFrom-Json + $jsonContent.Headers.Host | Should Be $uri.Authority } # Perform the following operation for Invoke-WebRequest using the following content types: "text/plain", "application/xml", "application/xml" @@ -1433,27 +1426,18 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { # gzip Returns gzip-encoded data. # deflate Returns deflate-encoded data. # $dataEncodings = @("Chunked", "Compress", "Deflate", "GZip", "Identity") - # Note: These are the supported options, but we do not have a web service to test them all. - # $dataEncodings = @("gzip", "deflate") --> Currently there is a bug for deflate encoding. Please see '7976639:Invoke-RestMethod does not support -TransferEncoding deflate' for more info. - $dataEncodings = @("gzip") - foreach ($data in $dataEncodings) - { - It "Invoke-RestMethod supports request that returns $data-encoded data." { - - $command = "Invoke-RestMethod -Uri http://httpbin.org/$data -TimeoutSec 5" - - $result = ExecuteWebCommand -command $command + # Note: These are the supported options, but we do not have a web service to test them all. + It "Invoke-RestMethod supports request that returns -encoded data." -TestCases @( + @{ DataEncoding = "gzip"} + @{ DataEncoding = "deflate"} + ) { + param($dataEncoding) + $uri = Get-WebListenerUrl -Test 'Compression' -TestValue $dataEncoding + $result = Invoke-RestMethod -Uri $uri -ResponseHeadersVariable 'headers' - # Validate response - if ($data -eq "gzip") - { - $result.Output.gzipped | Should Match $true - } - else - { - $result.Output.deflated | Should Match $true - } - } + # Validate response content + $headers.'Content-Encoding'[0] | Should Be $dataEncoding + $result.Headers.Host | Should Be $uri.Authority } # Perform the following operation for Invoke-RestMethod using the following content types: "text/plain", "application/xml", "application/xml" diff --git a/test/tools/Modules/WebListener/WebListener.psm1 b/test/tools/Modules/WebListener/WebListener.psm1 index 87a5899d300..7e8b4eea999 100644 --- a/test/tools/Modules/WebListener/WebListener.psm1 +++ b/test/tools/Modules/WebListener/WebListener.psm1 @@ -114,6 +114,7 @@ function Get-WebListenerUrl { [switch]$Https, [ValidateSet( 'Cert', + 'Compression', 'Delay', 'Encoding', 'Get', diff --git a/test/tools/WebListener/Controllers/CompressionController.cs b/test/tools/WebListener/Controllers/CompressionController.cs new file mode 100644 index 00000000000..b715f5db6c4 --- /dev/null +++ b/test/tools/WebListener/Controllers/CompressionController.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using mvc.Models; + +namespace mvc.Controllers +{ + public class CompressionController : Controller + { + public ActionResult Index() + { + string url = "/Compression/Gzip"; + ViewData["Url"] = url; + Response.Redirect(url, false); + return View("~/Views/Redirect/Index.cshtml"); + } + + [GzipFilter] + public JsonResult Gzip() + { + var getController = new GetController(); + getController.ControllerContext = this.ControllerContext; + return getController.Index(); + } + + [DeflateFilter] + public JsonResult Deflate() + { + var getController = new GetController(); + getController.ControllerContext = this.ControllerContext; + return getController.Index(); + } + + public IActionResult Error() + { + return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); + } + } +} diff --git a/test/tools/WebListener/DeflateFilter.cs b/test/tools/WebListener/DeflateFilter.cs new file mode 100644 index 00000000000..beab309b007 --- /dev/null +++ b/test/tools/WebListener/DeflateFilter.cs @@ -0,0 +1,30 @@ +using System; +using System.IO; +using System.IO.Compression; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.Filters; + +namespace mvc.Controllers +{ + internal sealed class DeflateFilter : ResultFilterAttribute + { + public override async Task OnResultExecutionAsync( ResultExecutingContext context, ResultExecutionDelegate next) + { + var httpContext = context.HttpContext; + using (var memoryStream = new MemoryStream()) + { + var responseStream = httpContext.Response.Body; + httpContext.Response.Body = memoryStream; + + await next(); + + using (var compressedStream = new DeflateStream(responseStream, CompressionLevel.Fastest)) + { + httpContext.Response.Headers.Add("Content-Encoding", new [] { "deflate" }); + memoryStream.Seek(0, SeekOrigin.Begin); + await memoryStream.CopyToAsync(compressedStream); + } + } + } + } +} diff --git a/test/tools/WebListener/GzipFilter.cs b/test/tools/WebListener/GzipFilter.cs new file mode 100644 index 00000000000..c15976beb7f --- /dev/null +++ b/test/tools/WebListener/GzipFilter.cs @@ -0,0 +1,30 @@ +using System; +using System.IO; +using System.IO.Compression; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.Filters; + +namespace mvc.Controllers +{ + internal sealed class GzipFilter : ResultFilterAttribute + { + public override async Task OnResultExecutionAsync( ResultExecutingContext context, ResultExecutionDelegate next) + { + var httpContext = context.HttpContext; + using (var memoryStream = new MemoryStream()) + { + var responseStream = httpContext.Response.Body; + httpContext.Response.Body = memoryStream; + + await next(); + + using (var compressedStream = new GZipStream(responseStream, CompressionLevel.Fastest)) + { + httpContext.Response.Headers.Add("Content-Encoding", new [] { "gzip" }); + memoryStream.Seek(0, SeekOrigin.Begin); + await memoryStream.CopyToAsync(compressedStream); + } + } + } + } +} diff --git a/test/tools/WebListener/README.md b/test/tools/WebListener/README.md index 802b4cc4fc9..528acf86c5d 100644 --- a/test/tools/WebListener/README.md +++ b/test/tools/WebListener/README.md @@ -59,6 +59,46 @@ Response when certificate is not provided in request: } ``` +## /Compression/Deflate/ +Returns the same results as the Get test with deflate compression. + +```powershell +$uri = Get-WebListenerUrl -Test 'Compression' -TestValue 'Deflate' +Invoke-RestMethod -Uri $uri -Headers $headers +``` + +```json +{ + "args": {}, + "origin": "127.0.0.1", + "headers": { + "User-Agent": "Mozilla/5.0 (Windows NT; Windows NT 10.0; en-US) WindowsPowerShell/5.1.15063.608", + "Host": "localhost:8083" + }, + "url": "http://localhost:8083/Compression/Deflate" +} +``` + +## /Compression/Gzip/ +Returns the same results as the Get test with gzip compression. + +```powershell +$uri = Get-WebListenerUrl -Test 'Compression' -TestValue 'Gzip' +Invoke-RestMethod -Uri $uri -Headers $headers +``` + +```json +{ + "args": {}, + "origin": "127.0.0.1", + "headers": { + "User-Agent": "Mozilla/5.0 (Windows NT; Windows NT 10.0; en-US) WindowsPowerShell/5.1.15063.608", + "Host": "localhost:8083" + }, + "url": "http://localhost:8083/Compression/Gzip" +} +``` + ## /Delay/ Returns the same results as the Get test. If a number is supplied, the server will wait that many seconds before returning a response. This can be used to test timeouts. From 30fb7e77f11ffdfef92280a6d58532ad0a8b3701 Mon Sep 17 00:00:00 2001 From: markekraus Date: Fri, 29 Sep 2017 05:41:36 -0500 Subject: [PATCH 2/7] [Feature] Run Feature tests From 8567a5e6f638a31febe90ddd91398fa41d8c1532 Mon Sep 17 00:00:00 2001 From: markekraus Date: Fri, 29 Sep 2017 12:31:57 -0500 Subject: [PATCH 3/7] [Feature] Address PR Feedback --- .../Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 | 8 ++++---- test/tools/WebListener/README.md | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 2f283101045..ddf9afd0c2d 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -605,9 +605,9 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { ValidateResponse -response $result # Validate response content - $result.Output.Headers.'Content-Encoding'[0] | Should Be $dataEncoding + $result.Output.Headers.'Content-Encoding'[0] | Should BeExactly $dataEncoding $jsonContent = $result.Output.Content | ConvertFrom-Json - $jsonContent.Headers.Host | Should Be $uri.Authority + $jsonContent.Headers.Host | Should BeExactly $uri.Authority } # Perform the following operation for Invoke-WebRequest using the following content types: "text/plain", "application/xml", "application/xml" @@ -1436,8 +1436,8 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { $result = Invoke-RestMethod -Uri $uri -ResponseHeadersVariable 'headers' # Validate response content - $headers.'Content-Encoding'[0] | Should Be $dataEncoding - $result.Headers.Host | Should Be $uri.Authority + $headers.'Content-Encoding'[0] | Should BeExactly $dataEncoding + $result.Headers.Host | Should BeExactly $uri.Authority } # Perform the following operation for Invoke-RestMethod using the following content types: "text/plain", "application/xml", "application/xml" diff --git a/test/tools/WebListener/README.md b/test/tools/WebListener/README.md index 528acf86c5d..6892000d954 100644 --- a/test/tools/WebListener/README.md +++ b/test/tools/WebListener/README.md @@ -72,7 +72,7 @@ Invoke-RestMethod -Uri $uri -Headers $headers "args": {}, "origin": "127.0.0.1", "headers": { - "User-Agent": "Mozilla/5.0 (Windows NT; Windows NT 10.0; en-US) WindowsPowerShell/5.1.15063.608", + "User-Agent": "Mozilla/5.0 (Windows NT; Microsoft Windows 10.0.15063 ; en-US) PowerShell/6.0.0", "Host": "localhost:8083" }, "url": "http://localhost:8083/Compression/Deflate" @@ -92,7 +92,7 @@ Invoke-RestMethod -Uri $uri -Headers $headers "args": {}, "origin": "127.0.0.1", "headers": { - "User-Agent": "Mozilla/5.0 (Windows NT; Windows NT 10.0; en-US) WindowsPowerShell/5.1.15063.608", + "User-Agent": "Mozilla/5.0 (Windows NT; Microsoft Windows 10.0.15063 ; en-US) PowerShell/6.0.0", "Host": "localhost:8083" }, "url": "http://localhost:8083/Compression/Gzip" From 184226c55ba80e8b73bd89a2fa2377e16527f40e Mon Sep 17 00:00:00 2001 From: markekraus Date: Fri, 29 Sep 2017 19:19:03 -0500 Subject: [PATCH 4/7] [Feature] Re-Run CI From ee4a81285629917a2b14cacf47dcb79ea53c0cf1 Mon Sep 17 00:00:00 2001 From: markekraus Date: Sat, 30 Sep 2017 07:17:33 -0500 Subject: [PATCH 5/7] [feature] Update WebListener Index page --- test/tools/WebListener/Views/Home/Index.cshtml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/tools/WebListener/Views/Home/Index.cshtml b/test/tools/WebListener/Views/Home/Index.cshtml index 7b4669ce334..8b914686652 100644 --- a/test/tools/WebListener/Views/Home/Index.cshtml +++ b/test/tools/WebListener/Views/Home/Index.cshtml @@ -2,6 +2,8 @@
  • / - This page
  • /Cert/ - Client Certificate Details
  • +
  • /Compression/Deflate/ - Returns deflate compressed response
  • +
  • /Compression/Gzip/ - Returns gzip compressed response
  • /Delay/{seconds} - Delays response for seconds seconds.
  • /Encoding/Utf8/ - Returns page containing UTF-8 data.
  • /Get/ - Emulates functionality of https://httpbin.org/get by returning GET headers, Arguments, and Request URL
  • From 9cd082ec039f87b7685a3fb85ab17b54c8aae829 Mon Sep 17 00:00:00 2001 From: markekraus Date: Sun, 1 Oct 2017 12:28:24 -0500 Subject: [PATCH 6/7] [Feature] Run Feature tests From d3b8335397ccb762c2d78c66c1e047f7487fe6c6 Mon Sep 17 00:00:00 2001 From: Mark Kraus Date: Mon, 2 Oct 2017 12:36:53 -0500 Subject: [PATCH 7/7] [Feature] Re-run CI