Request-level compression
Enable ASP.NET Core RequestDecompression middleware for gzip request bodies.
Full source
File: pwsh/tutorial/examples/22.6-Request-Compressed.ps1
<#!
22.6 Upload with request-level compression (RequestDecompression middleware)
Client example (PowerShell):
$boundary = 'req-boundary'
$body = @(
"--$boundary",
"Content-Disposition: form-data; name=note",
"",
"compressed",
"--$boundary",
"Content-Disposition: form-data; name=file; filename=hello.txt",
"Content-Type: text/plain",
"",
"hello",
"--$boundary--",
""
) -join "`r`n"
$bytes = [System.Text.Encoding]::UTF8.GetBytes($body)
$ms = [System.IO.MemoryStream]::new()
$gzip = [System.IO.Compression.GZipStream]::new($ms, [System.IO.Compression.CompressionMode]::Compress, $true)
$gzip.Write($bytes, 0, $bytes.Length)
$gzip.Dispose()
$compressed = $ms.ToArray()
Invoke-WebRequest -Method Post -Uri "http://127.0.0.1:$Port/upload" -ContentType "multipart/form-data; boundary=$boundary" -Headers @{ 'Content-Encoding'='gzip' } -Body $compressed
Cleanup:
Remove-Item -Recurse -Force (Join-Path ([System.IO.Path]::GetTempPath()) 'kestrun-uploads-22.6-request-compressed')
#>
param(
[int]$Port = 5000,
[IPAddress]$IPAddress = [IPAddress]::Loopback
)
New-KrLogger |
Set-KrLoggerLevel -Value Debug |
Add-KrSinkConsole |
Register-KrLogger -Name 'console' -SetAsDefault
New-KrServer -Name 'Forms 22.6'
Add-KrEndpoint -Port $Port -IPAddress $IPAddress | Out-Null
# Enable Request Decompression Middleware
Add-KrRequestDecompressionMiddleware -AllowedEncoding gzip | Out-Null
# Upload directory
$scriptName = [System.IO.Path]::GetFileNameWithoutExtension($PSCommandPath)
$uploadRoot = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath "kestrun-uploads-$scriptName"
# Add Rules
New-KrFormPartRule -Name 'file' -Required -AllowOnlyOne -AllowedContentTypes 'text/plain' |
New-KrFormPartRule -Name 'note' -Required |
Add-KrFormOption -DefaultUploadPath $uploadRoot -ComputeSha256 |
# Form Route
Add-KrFormRoute -Pattern '/upload' -ScriptBlock {
$files = $FormPayload.Files['file']
Write-KrJsonResponse -InputObject @{ count = $files.Count; files = $files } -StatusCode 200
}
Enable-KrConfiguration
# Start the server asynchronously
Start-KrServer
Step-by-step
- Logger: Enable console logging.
- Server: Create the host and bind a listener.
- Middleware: Add
Add-KrRequestDecompressionMiddlewarefor gzip. - Options: Configure upload storage and hashing.
- Route: Add
/uploadwithAdd-KrFormRoute. - Response: Return stored file metadata.
Try it
$boundary = 'req-boundary'
$body = @(
"--$boundary",
"Content-Disposition: form-data; name=note",
"",
"compressed",
"--$boundary",
"Content-Disposition: form-data; name=file; filename=hello.txt",
"Content-Type: text/plain",
"",
"hello",
"--$boundary--",
""
) -join "`r`n"
$bytes = [System.Text.Encoding]::UTF8.GetBytes($body)
$ms = [System.IO.MemoryStream]::new()
try {
$gzip = [System.IO.Compression.GZipStream]::new($ms, [System.IO.Compression.CompressionMode]::Compress, $true)
try {
$gzip.Write($bytes, 0, $bytes.Length)
} finally {
$gzip.Dispose()
}
# Ensure we send a raw byte[] body (not an enumerated Object[] of bytes)
[byte[]]$compressed = $ms.ToArray()
} finally {
$ms.Dispose()
}
Invoke-WebRequest -Method Post -Uri 'http://127.0.0.1:5000/upload' -ContentType "multipart/form-data; boundary=$boundary" -Headers @{ 'Content-Encoding'='gzip' } -Body $compressed
cat > payload.txt <<'EOF'
--req-boundary
Content-Disposition: form-data; name=note
compressed
--req-boundary
Content-Disposition: form-data; name=file; filename=hello.txt
Content-Type: text/plain
hello
--req-boundary--
EOF
gzip -c payload.txt | curl -X POST \
-H "Content-Encoding: gzip" \
-H "Content-Type: multipart/form-data; boundary=req-boundary" \
--data-binary @- \
http://127.0.0.1:5000/upload
Expected output
{
"count": 1,
"files": [
{ "name": "file", "fileName": "hello.txt", "length": 5, "sha256": "..." }
]
}
Notes
- Middleware: Request decompression must be enabled before parsing compressed bodies.
- Limits:
MaxRequestBodyBytesstill applies to decompressed size at the server level. - Logging: Request-level compression status is logged via
host.Logger. - PowerShell: If you build a helper function that returns a
byte[], ensure it returns a singlebyte[]object (avoid enumeration intoObject[]).
Troubleshooting
- 415 / Unsupported Content-Type: Ensure the request
Content-Typeismultipart/form-data; boundary=.... - 500 / Decompression errors: Ensure
Add-KrRequestDecompressionMiddleware -AllowedEncoding gzipis enabled and you send valid gzip bytes withContent-Encoding: gzip.
References
- Add-KrRequestDecompressionMiddleware
- Add-KrFormRoute
- New-KrServer
- Add-KrEndpoint
- Enable-KrConfiguration
- Write-KrJsonResponse
Previous / Next
Previous: Nested multipart/mixed Next: Part-level compression