Part-level compression

Decompress individual multipart parts using per-part Content-Encoding.

Full source

File: pwsh/tutorial/examples/22.7-Part-Compressed.ps1

<#!
    22.7 Upload with part-level compression (optional feature)

    Client example (PowerShell):
        $client = [System.Net.Http.HttpClient]::new()
        $content = [System.Net.Http.MultipartFormDataContent]::new()
        $raw = [System.Text.Encoding]::UTF8.GetBytes('compressed-part')
        $ms = [System.IO.MemoryStream]::new()
        $gzip = [System.IO.Compression.GZipStream]::new($ms, [System.IO.Compression.CompressionMode]::Compress, $true)
        $gzip.Write($raw, 0, $raw.Length)
        $gzip.Dispose()
        $compressed = $ms.ToArray()
        $part = [System.Net.Http.ByteArrayContent]::new($compressed)
        $part.Headers.ContentType = [System.Net.Http.Headers.MediaTypeHeaderValue]::Parse('text/plain')
        $part.Headers.ContentEncoding.Add('gzip')
        $content.Add($part,'file','payload.txt')
        $resp = $client.PostAsync("http://127.0.0.1:$Port/part-compressed", $content).Result
        $resp.Content.ReadAsStringAsync().Result

    Cleanup:
        Remove-Item -Recurse -Force (Join-Path ([System.IO.Path]::GetTempPath()) 'kestrun-uploads-22.7-part-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.7'

Add-KrEndpoint -Port $Port -IPAddress $IPAddress | Out-Null
# Upload directory
$scriptName = [System.IO.Path]::GetFileNameWithoutExtension($PSCommandPath)
$uploadRoot = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath "kestrun-uploads-$scriptName"
$maxDecompressedBytesPerPart = 1MB

# Add Rules
New-KrFormPartRule -Name 'file' -Required -AllowOnlyOne -AllowedContentTypes 'text/plain' |
    Add-KrFormOption -DefaultUploadPath $uploadRoot -ComputeSha256 -EnablePartDecompression -MaxDecompressedBytesPerPart $maxDecompressedBytesPerPart |
    Add-KrFormRoute -Pattern '/part-compressed' -ScriptBlock {
        $file = $FormPayload.Files['file'][0]
        Write-KrJsonResponse -InputObject @{ fileName = $file.OriginalFileName; length = $file.Length; sha256 = $file.Sha256 } -StatusCode 200
    }

Enable-KrConfiguration

# Start the server asynchronously
Start-KrServer

Step-by-step

  1. Logger: Enable console logging.
  2. Server: Create the host and bind a listener.
  3. Options: Enable per-part decompression and set decompressed limits.
  4. Route: Add /part-compressed with Add-KrFormRoute.
  5. Response: Return metadata for the decoded file part.

Try it

$client = [System.Net.Http.HttpClient]::new()
$content = [System.Net.Http.MultipartFormDataContent]::new()
$raw = [System.Text.Encoding]::UTF8.GetBytes('compressed-part')
$ms = [System.IO.MemoryStream]::new()
$gzip = [System.IO.Compression.GZipStream]::new($ms, [System.IO.Compression.CompressionMode]::Compress, $true)
$gzip.Write($raw, 0, $raw.Length)
$gzip.Dispose()
$compressed = $ms.ToArray()
$part = [System.Net.Http.ByteArrayContent]::new($compressed)
$part.Headers.ContentType = [System.Net.Http.Headers.MediaTypeHeaderValue]::Parse('text/plain')
$part.Headers.ContentEncoding.Add('gzip')
$content.Add($part,'file','payload.txt')
$client.PostAsync('http://127.0.0.1:5000/part-compressed', $content).Result.Content.ReadAsStringAsync().Result
printf 'compressed-part' > payload.txt
gzip -c payload.txt > payload.gz
curl -F "file=@payload.gz;type=text/plain;headers=Content-Encoding: gzip" http://127.0.0.1:5000/part-compressed

Expected output

{
  "fileName": "payload.txt",
  "length": 15,
  "sha256": "..."
}

Notes

  • Optional: Part-level decompression is disabled by default.
  • Limits: MaxDecompressedBytesPerPart protects against decompression bombs.
  • Logging: Part encoding decisions are logged via host.Logger.

Troubleshooting

  • No decompression: Ensure the part has Content-Encoding: gzip and EnablePartDecompression is enabled in options.
  • 415 / Unsupported Content-Encoding: Ensure the part encoding is one of the allowed encodings.

References


Previous / Next

Previous: Request-level compression Next: OpenAPI: basic multipart upload